Part III • Working with Others
and get every ounce of performance out of it. (Remember, though, that it is easy to create assembly functions that are not as efficient as a function written in C and compiled with the compiler’s optimization turned on.)
Your project is on a tight schedule, so you must purchase a library of functions to save development time.
When you purchasea library of functions, be sureit includes thesourcecode. You cannot depend on the supplier of the code to respond to your needs, and without source code you are on your own. I have never used code written by someone else without making at least one change. As well, if the supplier goes out of business, you can keep your product running if you have source code.
Peter’s rule: When you buy a library of functions, get the source code. If it is unavailable, look for a different product.
Other Languages
This chapter considers four languages other than C: assembly, BASIC, FORTRAN, and Pascal. All have been around for many years and are standardized. If your program must interface with a language not mentioned in this chapter, do not despair. Check whether the language you are using calls functions in a manner similar to one of the languages described here.
Table 11.1 shows the types of routines for each language. The major difference is that in FORTRAN a function returns a value, but a subroutine does not have a return value. When a function executes, a dummy variable with the same name as the function is created to hold the return value. (An example of this is shown in Listing 11.7, later in this chapter.)
C and Other Languages |
C C C |
|
11C |
|
C C C |
|
C C |
Table 11.1. Routine types for different languages.
Language |
Returns a value |
Has no return |
value |
|
|
assembly |
Procedure |
Procedure |
BASIC |
FUNCTION |
Subprogram |
C |
function |
(void) function |
FORTRAN |
FUNCTION |
SUBROUTINE |
Pascal |
Function |
Procedure |
|
|
|
Do not ignore your C compiler’s power. Almost all C compilers produce a mixed (or perhaps a pure) assembly listing of the functions being compiled. Typical assemblylisting options that you can use are shown in Table 11.2.
Table 11.2. C compiler assembly-listing options.
Option |
Description |
Compiler |
/Fa |
Produces an assembly |
Microsoft |
|
output file |
|
/Fc |
Produces a mixed object |
Microsoft |
|
and source listing file |
|
/Fl |
Produces an object |
Microsoft |
|
listing file |
|
/S |
Produces a mixed |
Borland C++ |
|
assembly/source listing |
|
|
file |
|
WDISASM |
Produces (with options) |
Watcom |
(a stand-alone |
assembly/object listing |
|
program) |
files |
|
|
|
|
Part III • Working with Others
If you use the options listed for Microsoft compilers, you must use the full compiler, not QuickC or QuickC for Windows. Neither of the QuickC compilers produces an assembly or object listing.
Watcom’s utility (WDISASM) has a number of options documented in the manual. It can disassemble .OBJ files produced by any Microsoft compatible compiler (one that produces compatible .OBJ files). You must check that the disassembly is correct, however, because not all .OBJ files disassemble correctly. Sometimes, disassembly by hand (a long and tedious process) is the only way to find out what the compiler did for a given block of code.
Do not overlook using the DOS DEBUG command to look at .EXE and .OBJ files. It has a crude disassembler, and it can help you see what is happening. Most debuggers can provide a disassembly listing as well.
Some compilers (such as Watcom’s C/386) do not provide an assembly listing, but do come with a utility program to produce assembly. In Watcom, for example, the WDISASM utility disassembles an .OBJ file.
You can save hours of programming if you use the compiler’s assembly listing option to produce an assembly program that is compatible with C programs. You can save time also if you already know the arguments that are passed to the function. Create a dummy function with as much of the necessary functionality as possible, then use the output of the compiler’s assembly listing as the starting point for your assembly routine.
Assembly
Assembly is not a language. Rather, it is a method to use the CPU’s native machine language. You must specify everything when writing in assembly: where data objects come from, where they will go, the basic operations, and so on. To use assembly language, you must be very familiar with how the CPU works.
Listing 11.1, CALLASM, is a simple example of how assembly works. It is written in assembly, and can be linked with the C libraries.
C and Other Languages |
C C C |
|
11C |
|
C C C |
|
C C |
Listing 11.1. CALLASM.ASM.
;
;CALLASM.ASM: This program calls the C printf() function
; |
and prints a string on the terminal. |
|
; |
|
|
|
|
|
NAME |
CALLASM |
|
|
|
EXTRN |
_printf:BYTE |
; Prototype for |
printf() |
|
|
|
|
|
EXTRN |
_ _acrtused:BYTE |
; Used to initialize C |
|
|
|
; |
startup code |
DGROUP |
GROUP |
_DATA,CONST,_BSS |
; Establish the DGROUP |
_TEXT |
SEGMENT |
WORD PUBLIC ‘CODE’ |
; Name the code |
|
|
|
; |
segment _TEXT |
|
ASSUME |
CS:_TEXT,DS:DGROUP,SS:DGROUP |
|
|
PUBLIC |
_main |
; Our function is |
|
|
|
; |
main() |
_main: |
mov |
word ptr nCount,0000H |
; Initialize nCount to |
|
|
|
; |
zero |
|
mov |
ax,offset DGROUP:szBuffer |
; Get address of |
|
|
|
; |
szBuffer[] |
|
push |
ax |
; Push on stack as the |
|
|
|
; |
last\parameter to |
printf() |
|
|
|
|
|
mov |
ax,offset DGROUP:L1 |
; Get format string |
|
|
|
; |
address |
|
push |
ax |
; Push on stack as the |
|
|
|
; |
next parameter to |
|
|
|
; |
printf() |
|
call |
near ptr _printf |
; Now call printf() |
|
add |
sp,0004H |
; Discard printf()’s |
|
|
|
; |
parameters |
|
mov |
word ptr nCount,ax |
; Save printf()’s |
|
|
|
; |
return value |
|
|
|
; Done, return to |
|
|
|
; |
caller |
_TEXT |
ENDS |
|
|
|
_DATA |
SEGMENT |
WORD PUBLIC ‘DATA’ |
; Set up the data |
|
|
|
; |
segment |
continues
Part III • Working with Others
Listing 11.1. continued
|
|
|
; PUBLIC is the same |
|
|
|
; |
as C’s |
|
|
|
; extern variables |
|
PUBLIC |
szBuffer |
; szBuffer is a public |
|
|
|
; |
name |
|
PUBLIC |
nCount |
; nCount is a public |
|
|
|
; |
name |
szBuffer |
LABEL |
BYTE |
|
|
|
DB |
“This is an assembly program.” |
|
|
DB |
0aH,00H |
; append the \n for |
|
|
|
; |
newline |
nCount |
LABEL |
BYTE |
|
|
|
DB |
00H,00H |
; nCount, init to zero |
_DATA |
ENDS |
|
|
|
CONST |
SEGMENT |
WORD PUBLIC ‘CONST’ |
|
|
L1 |
LABEL |
BYTE |
|
|
|
DB |
“%s”,00H |
; Our format string, a |
|
|
|
; |
constant, in the |
|
|
|
; |
CONST |
|
|
|
; |
segment |
CONST |
ENDS |
|
|
|
_BSS |
SEGMENT WORD PUBLIC ‘BSS’ |
; The BSS segment is |
|
|
|
; |
used |
|
|
|
; |
by C to find the |
|
|
|
; |
stack and |
|
|
|
; |
has other uses, |
|
|
|
; |
including |
|
|
|
; |
storage for global |
|
|
|
; |
variables |
|
|
|
; |
not initialized |
|
|
|
; |
explicitly |
_BSS |
ENDS |
|
; |
by the program |
|
END |
|
; End of our program |
|
|
|
|
|
C and Other Languages |
C C C |
|
11C |
|
C C C |
|
C C |
Nobody recommends that you write an assembly program that calls C functions. Instead, write the program as a C program, then call the functions coded in assembly from C.
FORTRAN
FORTRAN was the first programming language developed, although the first compilers were created by Grace Hopper in the early 1950s. These compilers were simple and inefficient, and the “languages” they supported were never named.
FORTRAN (short for FORmula TRANslation) can trace its roots to the early 1950s, when John Backus and Irving Ziller at IBM set out to develop a new computer language for the soon to be released IBM 704 computer. The development team grew to many more members, and in April 1957, they completed the first FORTRAN compiler.
The IBM 704 was the first computer to implement floating point in hardware. Until that time, computers used software emulation to perform floating-point math.
A typical FORTRAN program is shown in Listing 11.2, DEMO.FOR.
Listing 11.2. DEMO.FOR.
*DEMO.FOR
*A simple, typical FORTRAN program. This program
*is equivalent to the standard HELLO.C program.
*2345678----
program hello
print *, ‘Hello (FORTRAN)’
end
Part III • Working with Others
Pascal
Pascal is taught extensively at schools and universities, but has never caught on in a nonacademic environment, mostly due to the lack of good compilers. Apple released a UCSD Pascal system for the Apple II, but the implementation was crude and almost impossible to use productively, requiring a custom operating system incompatible with the existing Apple II operating system. Pascal became popular on PCs due only to the efforts of Borland, who released a good and inexpensive compiler called Turbo Pascal.
Although Pascal is still used today (and some Pascal compilers, most notably Turbo Pascal, remain), you will seldom see libraries of Pascal code that you will want to include in your C application. It is more likely you will have to convert a Pascal program to C. This conversion is easier if you can call Pascal functions from the C code, and convert each function one at a time. A typical Pascal program is shown in Listing 11.3.
Listing 11.3. HELLO.PAS.
/* HELLO.PAS
*A simple, typical Pascal program. This program
*is equivalent to the standard HELLO.C program.
*/
program hello
begin
writeln(‘Hello, from Pascal’);
end.
The example program looks very much like a C program. The comments are delimited in the same manner (using /* and */), statements end with a semicolon, and the begin and end keywords are similar to braces in C.
C and Other Languages |
C C C |
|
11C |
|
C C C |
|
C C |
BASIC
BASIC (Beginner’s All-Purpose Symbolic Instruction Code) is the first language used by most beginning programmers. It is simple and easy to learn, but not used for serious programming due to its limitations.
There are few reasons to interface BASIC code with C and even fewer methods. Several BASIC compilers are available, but none produce code compatible with C code created with a C compiler. The best way to interface BASIC and C is to convert the BASIC code to C, producing a new program that is bound to be better than the original.
A simple BASIC program is shown in Listing 11.4, HELLO.BAS. It’s the shortest example of a hello program!
Listing 11.4. HELLO.BAS.
PRINT “Hello”
Calling Other Languages from C
Usually, you write the main body of your program in C. Then you may use a few functions written in another language because you want to enhance the speed of the program (assembly code can be much faster than code written in a higher level language) or because you do not want to rewrite the functions in C.
This section describes how to create a basic C application and how to call a function created in another language. First, the main program is created in C, as shown in Listing 11.5, CALLNOTC.C. This program calls a non-C function called max() to determine the maximum of two numbers.
Listing 11.5. CALLNOTC.C.
/* CALLNOTC program, written 1992 by Peter D. Hipson */
Listing 11.5./* This C program calls C, FORTRAN, or assembly */
continues
Part III • Working with Others
Listing 11.5. continued
#include <stdio.h> #include <stddef.h> #include <stdlib.h> #include <string.h> #include <time.h>
int |
cdecl maximum(int nVar1, int nVar2); |
int |
main() |
{ |
|
int |
nVar1 = 0; |
int |
nVar2 = 1; |
char szBuffer[256];
printf(“Enter the same number twice to end\n”);
while(nVar1 != nVar2)
{
printf(“Enter two integers, separated with blanks”);
gets(szBuffer);
sscanf(szBuffer, “%d %d”, &nVar1, &nVar2);
printf(“The values entered are %d and %d. The larger is %d\n”, nVar1,
nVar2,
maximum(nVar1, nVar2));
}
return(0);
}
/* This is maximum() written in C */ int maximum(
C and Other Languages |
C C C |
|
11C |
|
C C C |
|
C C |
{
if (nVar1 < nVar2)
{
return(nVar2);
}
else
{
return(nVar1);
}
}
In the maximum() function, four lines of code do most of the work: a compare and two return values. Many programmers consider multireturns in a single function to be poor programming style. I do not agree, but I do not use goto except to a single label near the end of the function just before the cleanup code.
To see what a typical C compiler does with the maximum() function, look at the following output from the Microsoft C 7.00 compiler (without optimization):
|
|
_maximum: |
|
*** 00008a |
55 |
|
push |
bp |
*** 00008b |
8b |
ec |
mov bp,sp |
*** 00008d |
81 |
ec 00 00 |
|
sub sp,OFFSET L00390 |
*** 000091 |
56 |
|
push |
si |
*** 000092 |
57 |
|
push |
di |
;; Line 50 if (nVar1 < nVar2)
***000093 8b 46 06 mov ax,WORD PTR 6[bp]
***000096 39 46 04 cmp WORD PTR 4[bp],ax
*** 000099 |
7c |
03 e9 00 |
00 |
jge L00387 |
; ; Line 51 |
|
{ |
|
|
|
; ; Line 52 |
|
|
return(nVar2); |
|
*** 00009e |
8b |
46 06 |
mov ax,WORD PTR 6[bp] |
*** 0000a1 |
e9 |
00 00 |
jmp L00386 |
; ; Line 53 |
|
} |
|
|
|
; ; Line 54 |
|
else |
|
|
|
*** 0000a4 |
e9 |
00 00 |
jmp L00388 |
|
|
|
L00387: |
|
|
; Line 54 |
else (continued...) |
|
continues