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

Advanced C 1992

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

Part III • Working with Others

Listing 11.5. continued

; ; Line 55

{

 

 

 

; ;

Line 56

 

return(nVar1);

 

***

0000a7

8b

46 04

mov

ax,WORD PTR 4[bp]

 

***

0000aa

e9

00 00

jmp

L00386

; ;

Line 57

}

 

 

 

L00388:

;; Line 58}

;Line 58 (end of the function, cleanup:)

 

 

L00386:

 

*** 0000ad

5f

 

pop di

*** 0000ae

5e

 

pop si

*** 0000af

8b

e5

mov sp,bp

*** 0000b1

5d

 

pop bp

*** 0000b2

c3

 

ret OFFSET 0

Local Size: 2

; Line 0

Next, Microsoft C’s /Ox (maximum optimize) switch was turned on so that you could see what a compiler can do using maximum optimization. The following output was produced:

 

 

 

_maximum:

 

***

00007a

55

push

bp

***

00007b

8b

ec

mov bp,sp

;nVar1 = 4

;nVar2 = 6

***00007d 8b 56 04 mov dx,WORD PTR [bp+4] ;nVar1

***000080 8b 5e 06 mov bx,WORD PTR [bp+6] ;nVar2

;|***

if (nVar1 < nVar2)

 

; Line 50

 

 

 

 

*** 000083

3b

da

cmp bx,dx

*** 000085

7e

05

jle $I433

;|***

{

 

 

 

;|***

 

return(nVar2);

 

; Line 52

 

 

 

*** 000087

8b

c3

mov ax,bx

*** 000089

5d

 

pop bp

***

00008a

c3

 

ret

***

00008b

90

 

nop

446

C and Other Languages

C C C

 

11C

 

C C C

 

C C

;|***

}

 

 

;|***

else

 

 

; Line 54

 

 

 

 

 

$I433:

 

;|***

{

 

 

;|***

 

return(nVar1);

 

; Line 56

 

 

 

*** 00008c

8b c2

mov ax,dx

;|***

}

 

 

;|*** }

 

 

 

; Line 58

 

 

 

*** 00008e

5d

pop bp

*** 00008f

c3

ret

_maximum ENDP _TEXT ENDS

END ;|***

;|*** // #endif

Notice that the optimized code is slightly smaller and a bit more complex. This code might be more difficult to debug, but this drawback is unimportant because code is seldom debugged at the machine-language level after optimization.

Calling Assembly from C

Can a programmer using assembly language write a smaller, faster function than the compiler? To test this, I wrote the maximum() function in assembly. So that I would not be biased by looking at what the compiler produced for optimized code, I wrote the assembly function before I produced the two listings of maximum() shown in the preceding section.

Listing 11.6 is my version of maximum(). It is a bit shorter and faster than the version from the compiler, even when the compiler version is fully optimized.

Listing 11.6. MAXIMUM.ASM.

;

;A hand optimized assembly function for C.

;cmacros.inc are a handy group of macros that make

continues

447

Part III • Working with Others

Listing 11.6. continued

;

writing C-compatible functions easier.

;

 

include e:\windev\include\cmacros.inc

;

;int maximum(int, int);

;This version was optimized by hand for both

;minimum size and fastest execution. The

;compiler’s code is twice as long.

;

 

 

;

 

 

 

NAME

MAXIMUM

DGROUP

GROUP

_DATA

_TEXT

SEGMENT

WORD PUBLIC ‘CODE’

 

ASSUME

CS:_TEXT,DS:DGROUP,SS:DGROUP

 

PUBLIC

_maximum

_maximum:

enter

0000H,00H

 

mov

ax,word ptr +6H[bp]

 

cmp

word ptr +4H[bp],ax

 

jle

short L6

 

mov

ax,word ptr +4H[bp]

L6:

nop

;Handy label target...

 

leave

 

 

ret

 

_TEXT

ENDS

 

_DATA

SEGMENT

WORD PUBLIC ‘DATA’

_DATA

ENDS

 

 

END

 

 

 

 

448

C and Other Languages

C C C

 

11C

 

C C C

 

C C

In my version of maximum(), I used the enter and leave operands, which are useful for creating functions called by higher level languages such as C.

One of the tested values is returned in AX. If the value in AX is the larger of the two values, AX does not need to be reloaded and can just return that value. Otherwise, the other value is placed in AX and then returned.

Because this version is optimized by hand, it executes faster and makes better use of memory. For more complex functions, however, this improvement is more difficult to obtain. By breaking your assembly code into smaller and smaller parts and analyzing the resultant code, you can be confident that it will be faster without performing some extensive benchmarks.

Calling FORTRAN and Pascal from C

Writing maximum() in FORTRAN is an easy task, as shown in Listing 11.7. Optimization is less of a concern in FORTRAN than in assembly because FORTRAN is a high-level language. Not all C compilers support FORTRAN functions.

Listing 11.7. The maximum() function in FORTRAN.

*

* The C function maximum() written in FORTRAN

*

integer function maximum(nVar1, nVar2) integer*2 nVar1, nVar2

maximum = nVar2

if (nVar1 .gt. nVar2) maximum = nVar1

end

When this function is called from C, the calling C program file must tell the C compiler that the function is written in FORTRAN. This is accomplished by properly declaring the maximum() function:

int __fortran maximum(int, int);

449

Part III • Working with Others

The call fails if the function is not declared correctly (using the __fortran keyword) because of the way that the arguments are passed to a FORTRAN program’s functions. Except for the differences in languages, functions written in FORTRAN and in Pascal are handled the same way.

Calling C Functions from Other Languages

The opposite of calling from C a function written in another language is calling from a second language a function written in C. There are several problems in doing this. For example, many C library functions rely on the execution of C initialization code, which may not be present when a program written in another language calls a C function. You can partially alleviate this problem in assembly by writing the program’s main function in C, thereby forcing the assembly program to behave like a C program.

A C program can grow quite large when it is linked, so many programmers write in assembly to keep the program smaller. If the C function called from another language does not make any calls to C library functions, no library functions are included in the executable program. This makes the program smaller and eliminates the task of ensuring that C has properly initialized itself.

This section presents a few examples of other languages calling a C function. These examples use CALLNOTC.C (Listing 11.5), which was used also in the previous section. The maximize() function is written in C (see Listing 11.8), and the main, calling program is written in another language. Because maximize() does not call any other functions, I did not have to address the issue of calling C’s startup code. However, I have included the necessary mechanism to initialize C, in case you need it.

Listing 11.8. MAXIMUM.C.

/* MAXIMUM.C function, written 1992 by Peter D. Hipson */

/* This is a C function called by FORTRAN or assembly */

#include <stdio.h> #include <stddef.h>

450

C and Other Languages

#include <stdlib.h>

#include

<string.h>

#include

<time.h>

int cdecl maximum(int nVar1, int nVar2);

int

maximum(

int

nVar1,

int

nVar2)

{

 

if (nVar1 < nVar2)

{

return(nVar2);

}

else

{

return(nVar1);

}

}

C C C

C11C C

C C C

The maximum() function could be written in assembly, but some other function that must do special things such as interact with hardware might have to be written in assembly.

Calling C from Assembly

An assembly program can call a C function, subject to either of two conditions. One, the C library must be linked with the assembly program. Any C functions called (CALLNOTC, in Listing 11.5, calls several) are processed by library functions, whose references must be resolved.

Two, the C library’s startup code must be included and called. With Microsoft C, this is accomplished by linking with the necessary library (I used SLIBCE.LIB in developing CALLNOTC.ASM, in Listing 11.9) and defining the external symbol, _acrtused. When the startup code from the C library is executed, it properly initializes the C environment.

451

Part III • Working with Others

Listing 11.9. CALLNOTC.ASM.

;/* CALLNOTC program, written 1992 by Peter D. Hipson */

;

;/* This is an assembly program that calls FORTRAN or assembly */

;

;#include <stdio.h> ;#include <stddef.h> ;#include <stdlib.h> ;#include <string.h> ;#include <time.h>

;

;int cdecl maximum(int nVar1, int nVar2);

;

; Enable 386 instruction set

.386

NAME callnotc

; maximum(), sscanf(), gets(), and printf() are called

EXTRN _maximum:BYTE

EXTRN _sscanf:BYTE

EXTRN _gets:BYTE

EXTRN _printf:BYTE

; _acrtused is used to initialize C at runtime

EXTRN _ _acrtused:BYTE

;The datagroup is _DATA (misc data), CONST (constants),

;and _BSS (uninitialized data)

DGROUP

GROUP

_DATA,CONST,_BSS

_TEXT

SEGMENT

WORD PUBLIC USE16 ‘CODE’

 

ASSUME

CS:_TEXT,DS:DGROUP,SS:DGROUP

;The program’s main function, called by C’s startup code.

;Microsoft C naming conventions require the underscore

452

C and Other Languages

;prefix. Other compilers may use an underscore

;following the name.

 

PUBLIC

_main

 

_main:

push

bp

; Start up, save registers,

 

mov

bp,sp

; and get ready to run

 

sub

sp,0000H

 

 

push

si

 

 

push

di

 

; Initialize nVar1 and nVar2 so that they are not the same!

 

mov

word ptr -104H[bp],0000H

 

mov

word ptr -106H[bp],0001H

; Call to printf(szMsg1);

 

mov

ax,offset DGROUP:szMsg1

 

push

ax

 

call

near ptr _printf

 

add

sp,0002H

 

jmp

near ptr Loop1

; Loop back to Loop1

 

Loop1:

mov

ax,offset DGROUP:szMsg2

 

push

ax

 

call

near ptr _printf

 

add

sp,0002H

 

lea

ax,-102H[bp]

 

push

ax

 

call

near ptr _gets

 

add

sp,0002H

 

lea

ax,-106H[bp] ; nVar2’s address

 

push

ax

 

lea

ax,-104H[bp] ; nVar1’s address

 

push

ax

C C C

C11C C

C C C

continues

453

Part III • Working with Others

Listing 11.9. continued

 

mov

ax,offset DGROUP:szScanFormat

 

push

ax

 

 

 

lea

ax,-102H[bp]

; szBuffer (auto var on stack)

 

push

ax

 

 

 

call

near ptr _sscanf

 

 

 

add

sp,0008H

 

 

 

push

word ptr -106H[bp]

; nVar2

 

push

word ptr -104H[bp]

; nVar1

 

call

near ptr _maximum

 

 

add

sp,0004H

 

 

 

push

ax

 

 

 

push

word ptr -106H[bp]

; nVar2

 

push

word ptr -104H[bp]

; nVar1

 

mov

ax,offset DGROUP:szPrintFormat

 

push

ax

 

 

 

call

near ptr _printf

 

 

 

add

sp,0008H

 

 

 

mov

ax,word ptr -106H[bp]

 

cmp

word ptr -104H[bp],ax

 

je

short AllDone

 

; We are finished

 

jmp

near ptr Loop1

 

; Go around another time

AllDone:

mov

ax,0000H

 

; A zero return code

 

jmp

near ptr Dummy

 

 

Dummy:

pop

di

 

; Clean up and go home

 

pop

si

 

 

 

mov

sp,bp

 

 

 

pop

bp

 

 

 

ret

 

 

 

_TEXT

ENDS

 

 

 

_DATA

SEGMENT

WORD PUBLIC USE16 ‘DATA’

454

 

 

C and Other Languages

C C C

 

 

 

11C

 

 

 

C C C

szMsg1

LABEL

BYTE

C C

 

 

DB

“Enter the same number twice to end”, 0AH, 00H

szMsg2

LABEL

BYTE

 

 

DB

“Enter two integers, separated with blanks”, 00H

szScanFormat

LABEL

BYTE

 

 

DB

“%d %d”, 00H

 

szPrintFormat

LABEL

BYTE

 

 

DB

“The values entered are %d and %d, “

 

 

DB

“the larger is %d”,0AH, 00H

 

_DATA

ENDS

 

 

CONST

SEGMENT

WORD PUBLIC USE16 ‘CONST’

 

CONST

ENDS

 

 

_BSS

SEGMENT

WORD PUBLIC USE16 ‘BSS’

 

_BSS

ENDS

 

 

END

The program calls not only the C function (maximum()), but also a number of other library functions, including printf(), gets(), and scanf(). These functions form the basic I/O for the program. DOS I/O interrupt routines could have been called directly, but because they do not do formatted I/O, the program would have to convert the typed characters to integer numbers and convert the numbers back to characters for output.

To summarize, write the main program in C (or another high-level language) if possible. Then write in assembly the routines whose speed or size is critical. When using an advanced compiler (such as Microsoft’s C 7.0), you can control how much of the library code is included, the arrangement of the program’s segments (whether there are separate data and code segments or a single segment for both), and the allocation and use of memory.

When programming on a PC (under DOS), do not forget the available DOS services. These services, listed in Table 11.3, are accessed using the Int 21 instruction. If you are using a different operating system, it should have similar functions.

455