Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Advanced C 1992

.pdf
Скачиваний:
92
Добавлен:
17.08.2013
Размер:
4.28 Mб
Скачать

 

 

 

 

 

 

Pointers and Indirection

 

C C C

 

 

 

 

 

 

 

 

C3C

 

 

 

 

 

 

 

 

C C C

;|***

 

 

 

 

 

 

C

 

 

 

 

 

 

 

 

;|***

return(nCount);

 

 

 

 

 

 

; Line 38

 

 

 

 

 

 

 

 

*** 000044

8b

46 fc

mov

ax,WORD PTR [bp-4]

;nCount

*** 000047

8b

e5

mov

sp,bp

 

 

 

*** 000049

5d

 

pop

bp

 

 

 

 

*** 00004a

c3

 

ret

 

 

 

 

 

*** 00004b

90

 

nop

 

 

 

 

 

_NumberWords

ENDP

 

 

 

 

 

 

 

_TEXT

ENDS

 

 

 

 

 

 

 

 

END

 

 

 

 

 

 

 

 

;|*** }

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Listing 3.7 is the assembly listing for the version of NumberWords() that uses an index to the passed array. As in the preceding example, the compiler produces this machine code, commented with the original source lines, when the function is compiled.

Listing 3.7. NUMWORD4.COD, the assembly listing for the array indexed version of NumberWords().

;Edited for size.

;Static Name Aliases

TITLE numword4.c NAME numword4

.8087

 

_TEXT

SEGMENT

WORD PUBLIC ‘CODE’

_TEXT

ENDS

 

_DATA

SEGMENT

WORD PUBLIC ‘DATA’

_DATA

ENDS

 

CONST

SEGMENT

WORD PUBLIC ‘CONST’

CONST

ENDS

 

_BSS

SEGMENT

WORD PUBLIC ‘BSS’

_BSS

ENDS

 

DGROUP

GROUP

CONST, _BSS, _DATA

ASSUME CS: _TEXT, DS: DGROUP, SS: DGROUP

continues

85

Part I • Honing Your C Skills

Listing 3.7. continued

EXTRN

--acrtused:ABS

EXTRN

--chkstk:NEAR

_TEXT

 

SEGMENT

ASSUME

CS: _TEXT

;|*** /* NUMWORD, written 20 May 1992 by Peter D. Hipson */

;|***

 

 

 

 

 

 

;|*** #include <stdio.h>

// Make includes first part of file

;|*** #include <string.h> // For string functions

;|***

 

 

 

 

 

 

;|*** #define

TRUE

1

 

 

;|*** #define

FALSE

0

 

 

;|***

 

 

 

 

 

 

;|***

 

 

 

 

 

 

;|*** int

 

NumberWords(char

* pString);

;|***

 

 

 

 

 

 

;|***

 

 

 

 

 

 

;|*** int

 

NumberWords(

 

 

 

;|***

char

szString[])

 

 

;|***

 

 

 

 

 

 

;|*** {

 

 

 

 

 

 

; Line 16

 

 

 

 

 

 

PUBLIC

 

_NumberWords

 

 

 

_NumberWords

PROC NEAR

 

 

 

*** 000000

55

 

 

push

bp

*** 000001

8b

ec

 

mov

bp,sp

*** 000003

b8

08 00

 

mov

ax,8

*** 000006

e8

00 00

 

call

--chkstk

*** 000009

56

 

 

push

si

;szString = 4

;i = -6

;nBlank = -2

;nCount = -4

;|***

;|*** int

i;

 

 

 

;|*** int

nBlank

= TRUE;

 

 

; Line 19

 

 

 

 

*** 00000a

c7

46 fe 01 00

mov

WORD PTR [bp-2],1

;nBlank

 

 

 

 

;|*** int

nCount

= 0;

 

 

86

 

 

 

 

 

 

Pointers and Indirection

 

C C C

 

 

 

 

 

 

 

 

 

 

C3C

 

 

 

 

 

 

 

 

 

 

C C C

; Line 20

 

 

 

 

 

 

 

 

 

C

 

 

 

 

 

 

 

 

 

 

*** 00000f

c7

46

fc 00 00

 

mov

WORD PTR [bp-4],0

 

;nCount

 

 

 

 

 

 

 

 

 

 

;|***

 

 

 

 

 

 

 

 

 

 

;|***

for (i = 0; szString[i]; i++)

 

 

 

 

 

; Line 22

 

 

 

 

 

 

 

 

 

 

*** 000014

c7

46

fa 00 00

 

mov

WORD PTR [bp-6],0

;i

*** 000019

eb 09

 

jmp

SHORT $F240

 

 

 

*** 00001b

90

 

 

nop

 

 

 

 

 

 

 

 

$I243:

 

 

 

 

 

 

;|***

{

 

 

 

 

 

 

 

 

 

;|***

 

if (szString[i] != ‘ ‘)

 

 

 

 

 

;|***

 

{

 

 

 

 

 

 

 

 

;|***

 

if (nBlank)

 

 

 

 

 

 

;|***

 

{

 

 

 

 

 

 

 

 

;|***

 

 

++nCount;

 

 

 

 

 

 

;|***

 

}

 

 

 

 

 

 

 

 

;|***

 

 

 

 

 

 

 

 

 

 

;|***

 

nBlank = FALSE;

 

 

 

 

 

 

;|***

 

}

 

 

 

 

 

 

 

 

;|***

 

else

 

 

 

 

 

 

 

 

;|***

 

{

 

 

 

 

 

 

 

 

; Line 34

 

 

 

 

 

 

 

 

 

 

;|***

 

nBlank = TRUE;

 

 

 

 

 

 

; Line 35

 

 

 

 

 

 

 

 

 

 

*** 00001c

c7

46

fe 01 00

 

mov

WORD PTR [bp-2],1

 

;nBlank

 

 

 

 

 

 

 

 

 

 

;|***

 

}

 

 

 

 

 

 

 

 

; Line 36

 

 

 

 

 

 

 

 

 

 

;|***

}

 

 

 

 

 

 

 

 

 

; Line 37

 

 

 

 

 

 

 

 

 

 

 

 

 

$FC241:

 

 

 

 

 

 

*** 000021

ff 46 fa

inc

WORD PTR [bp-6]

;i

 

 

 

 

 

$F240:

 

 

 

 

 

 

*** 000024

8b

5e

fa

mov

bx,WORD PTR [bp-6]

 

;i

 

*** 000027

8b

76

04

mov

si,WORD PTR [bp+4]

 

;szString

*** 00002a

8a

00

 

mov

al,[bx][si]

 

 

 

*** 00002c

88

46

f8

mov

BYTE PTR [bp-8],al

 

 

 

*** 00002f

0a

c0

 

or

al,al

 

 

 

 

*** 000031

74

15

 

je

$FB242

 

 

 

 

continues

87

Part I • Honing Your C Skills

Listing 3.7. continued

;|***

{

 

 

 

 

 

 

; Line 23

 

 

 

 

 

 

 

;|***

 

if (szString[i] != ‘ ‘)

 

 

 

 

; Line 24

 

 

 

 

 

 

 

*** 000033

3c 20

cmp

al,32

 

 

 

*** 000035

74 e5

je

$I243

 

 

 

;|***

 

{

 

 

 

 

 

; Line 25

 

 

 

 

 

 

 

;|***

 

if (nBlank)

 

 

 

 

 

; Line 26

 

 

 

 

 

 

 

*** 000037

83 7e fe 00

cmp

WORD PTR [bp-2],0

;nBlank

*** 00003b

74 03

je

$I244

 

 

 

;|***

 

{

 

 

 

 

 

; Line 27

 

 

 

 

 

 

 

;|***

 

++nCount;

 

 

 

 

 

; Line 28

 

 

 

 

 

 

 

*** 00003d

ff 46 fc

inc

WORD PTR [bp-4]

;nCount

;|***

 

}

 

 

 

 

 

; Line 29

 

 

 

 

 

 

 

;|***

 

 

 

 

 

 

 

;|***

 

nBlank = FALSE;

 

 

 

 

 

; Line 31

 

 

 

 

 

 

 

 

 

$I244:

 

 

 

 

 

*** 000040

c7 46 fe 00 00

 

mov

WORD PTR [bp-2],0

 

;nBlank

 

 

 

 

 

 

 

;|***

 

}

 

 

 

 

 

; Line 32

 

 

 

 

 

 

 

;|***

 

else

 

 

 

 

 

; Line 33

 

 

 

 

 

 

 

*** 000045

eb da

jmp

SHORT $FC241

 

 

*** 000047

90

nop

 

 

 

 

 

 

$FB242:

 

 

 

 

 

;|***

 

{

 

 

 

 

 

;|***

 

nBlank = TRUE;

 

 

 

 

 

;|***

 

}

 

 

 

 

 

;|***

}

 

 

 

 

 

 

;|***

 

 

 

 

 

 

 

88

 

 

 

 

 

 

Pointers and Indirection

 

C C C

 

 

 

 

 

 

 

 

C3C

 

 

 

 

 

 

 

 

C C C

;|***

return(nCount);

 

 

 

C

 

 

 

 

 

 

; Line 39

 

 

 

 

 

 

 

 

*** 000048

8b

46 fc

mov

ax,WORD PTR [bp-4]

;nCount

 

*** 00004b

5e

 

pop

si

 

 

 

 

*** 00004c

8b

e5

mov

sp,bp

 

 

 

 

*** 00004e

5d

 

pop

bp

 

 

 

 

*** 00004f

c3

 

ret

 

 

 

 

 

_NumberWords

ENDP

 

 

 

 

 

 

 

_TEXT

ENDS

 

 

 

 

 

 

 

 

END

 

 

 

 

 

 

 

 

;|*** }

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

The assembly listings show the major differences from what the original C version shows; you should consider several factors, however, when you are deciding whether to use indexing or to modify pointers:

Functions that use indexing often are easier to read and understand.

Functions that use indexing often generate more machine code than functions that use pointer modification. This situation is more prevalent in functions that have many references to the variable (or variables) accessed with pointers.

Functions that use indexing often are slower than functions that use pointer modification. This situation is more prevalent in functions that have many references to the variable (or variables) accessed with pointers, and occurs because the functions usually must add the index to the array base for each access.

Functions with array indexing require local variables that require stack space. This consideration usually is a minor one, but it may be a factor when stack usage must be either minimized or eliminated.

You should note that even though the example program used a string (which is a character array), the concepts are the same in other arrays, such as int, long, or float. The important thing with nonstring arrays is that the function the string is being passed to must know how many elements are found in the array, because only strings have a meaningful end marker, NULL.

89

Part I • Honing Your C Skills

Protecting Strings in Memory

If I could find a way to protect strings in memory, I would be rich. Seriously, the only thing that protects strings in memory is careful programming. Although many operating environments offer some forms of memory protection and some compilers offer bounds checking, this protection is limited and easily circumvented—often unknowingly by programmers.

A number of dangerous functions in the C language’s library don’t know how long a string is and easily can overwrite a string’s memory allocation without notifying the programmer. Even functions that tell you how much of the string they used have possibly already destroyed valuable memory when they write past the end of the string.

Two of the worst offenders are input/output functions and the various string functions. The input/output functions are often given a buffer in order to read in the desired information. The problem is that they don’t know how long the buffer is. In the following example fragment, the programmer made the assumption that a user never would enter a line longer than 80 characters:

char szBuffer[80]; // You’ll never read more than 80 characters // (ha-ha).

if (gets(szBuffer))

{

// Process the buffer inputted.

}

The programmer might have thought, for example, that the terminal to be used allowed only 80 characters per line. The user first used I/O redirection to provide input to the program, though, and the lines in the user’s file were about 200 characters long. Of course, the program crashed.

This problem doesn’t really have a fix that always works. The fix most often consists of putting a realistic maximum on the buffer size, which means that the buffer must be capable of holding a very large string. In the preceding example, it would not be unreasonable to define the input buffer to be several thousand bytes long. I usually create in my programs a generic buffer (called szTempBuffer), which is used for places where I don’t want to experience buffer overflow.

In the following example, a set of two strings has been defined and then concatenated, when necessary.

90

Pointers and Indirection

C C C

 

C3C

 

C C C

 

C

char

szMyName[] = {“Peter

D. Hipson”);

char

szMyAddress[]= {“New

Hampshire”);

// bFullAddress says that the user wants my full address:

if (bFullAddress)

{

strcat(szMyName, szMyAddress);

}

The only problem is that szMyName is not large enough to hold both strings. Crash—it’s over! Again, the fix is to be sure that the destination for the library string functions is large enough. One possible fix is to use szTempBuffer to hold the result of the concatenation and then test to see whether it fits into the final destination, as in this example:

strcpy(szTempBuffer, szMyName); strcat(szTempBuffer, szMyAddress);

if (strlen(szTempBuffer) > sizeof(szMyName))

{// Truncate the result to fit. szTempBuffer[sizeof(szMyName) - 1] = ‘\0’;

printf(“String ‘%s’ won’t fit into buffer\n”, szTempBuffer);

}

strcpy(szMyName, szTempBuffer);

Or if the preceding example doesn’t require that the operation take place if the number of characters being assigned to a string doesn’t fit, you can simply test and perform the operation if it fits:

if (strlen(szMyName) + strlen(szMyAddress) < sizeof(szMyName))

{

strcat(szMyName, szMyAddress);

}

else

{

printf(“String ‘%s%s’ won’t fit into buffer\n”, szMyName,

szMyAddress);

}

The primary difference is that the first example copies as many characters as will fit, and the second does not. For either example to work, the compiler must know how

91

Part I • Honing Your C Skills

large the strings are. It knows how large when the strings are declared in the source file, or when they are defined with sizes. Because you often define arrays by specifying their size, you can get into trouble when an error message tells you that the size of the object is unknown.

When you are using sprint() to print to a string, the function can cause innumerable problems because most format specifiers for floating-point numbers, when given an invalid value, print some rather strange results. Often, you assume that your numbers are always correct; that assumption is a weak one, however, because the majority of the numbers the program works with are provided by the user. In this case also, I try to use a large buffer, such as my szTempBuffer, to hold the results of sprintf() until I can be sure that the resulting string is not too large for the intended destination.

Ragged-Right String Arrays

There is a problem with using strings. Suppose that you have a program with a large number of strings, such as list of common sayings. Each line of the sayings is placed in a string buffer. If these strings are used as constants (they won’t be modified), you may well want to pack the strings together, with no wasted space.

A more common way of storing strings is shown in the program FIXSTR.C. It allocates an array of 25 lines, each of which is 80 characters long. The total storage required for this array is 2,000 bytes (see Listing 3.8).

Listing 3.8. FIXSTR.C.

/* FIXSTR, written 20 May 1992 by Peter D. Hipson */ /* Fixed-length strings in a program. */

#include <stdio.h> // Make includes first part of file #include <string.h> // For string functions.

#define MAX_LINES 25 #define MAX_LENGTH 80

int main(void); // Define main() and the fact that this program doesn’t // use any passed parameters.

92

 

 

Pointers and Indirection

C C C

 

 

 

C3C

 

 

 

C C C

int main()

 

C

 

 

{

 

 

 

int

i;

 

 

char

szSaying[MAX_LINES][MAX_LENGTH] =

 

 

{

 

 

 

“Firestone’s Law of Forecasting:”,

 

 

Chicken Little only has to be right once.”,

 

 

“”,

 

 

 

“”,

 

 

 

“Manly’s Maxim:”,

 

 

Logic is a systematic method of coming to”,

 

 

the wrong conclusion with confidence.”,

 

 

“”,

 

 

 

“”,

 

 

 

“Moer’s truism:”,

 

 

The trouble with most jobs is the job holder’s”,

 

 

resemblance to being one of a sled dog team. No one”,

 

gets a change of scenery except the lead dog.”, “”, “”,

“Cannon’s Comment:”,

If you tell the boss you were late for work because you”,

had a flat tire, the next morning you will have a flat tire.”

};

printf(

“Number of lines is %d\n” “size of item is %d\n” “size of (char) is %d\n”,

sizeof(szSaying) / sizeof(szSaying[0]), // Number of elements.

sizeof(szSaying[0]),

// Size of char *

sizeof(szSaying[0][0]));

// Size of char

switch (sizeof(char *))

 

{

 

case 2: // Near pointers

 

printf(“Addr len saying\n”);

 

break;

 

 

continues

93

Part I • Honing Your C Skills

Listing 3.8. continued

case 4: // Far pointers, 808x segmented pointers. printf(“Address len saying\n”);

break;

}

for (i = 0; i < sizeof(szSaying) / sizeof(szSaying[0]); i++)

{

printf(“%p %3d ‘%s’\n”, szSaying[i], strlen(szSaying[i]), szSaying[i]);

}

return (0);

}

Figure 3.2 shows an example of how the memory for FIXSTR.C’s szSaying is allocated and used. In this program, szSaying is a single, two-dimensional character array.

Figure 3.2. szSaying in FIXSTR.C.

94