beautypg.com

Measurement Computing Personal488 rev.3.0 For DOS & Windows 3.Xi User Manual

Page 114

background image

II. SOFTWARE GUIDES - 8. Driver488/DRV

8K. Other Languages

Personal488 User’s Manual, Rev. 3.0

II-99

#if defined(M_I86SM) || defined(M_I86MM)
int segment(ptr)
void near *ptr;
{ static struct SREGS segs = { 0, 0, 0, 0, };
if (segs.ds==0) segread(&segs);
return segs.ds;
}
#define offset(ptr) (int)ptr
#else
#define offset(ptr) ((unsigned)(fp))
#define segment(ptr) ((unsigned)((unsigned long)(fp) > 16))
#endif

The

#IF

statement checks if we are using the Small (

M_I86SM

) or Medium (

M_I86MM

) models

(Microsoft C does not support the Tiny model) and, if we are, defines a function segment that returns
the (constant) segment value that can be used for all data elements. The

segment

function takes a

pointer (

ptr

) as an argument, but does not use it. Instead, the first time it is called, it calls the

segread

library function to read the

ds

segment register and returns that value. Each subsequent time

segment

is called, it returns the saved

ds

register value. In these small-data models, the pointer to a

data object is just the

offset

address of that object, and so we define

offset(ptr)

as

(int)ptr

,

which is just an integer with the same value as the pointer.

If we are using a large-data model, data pointers are 32 bits, and the

segment

and

offset

must be

extracted from the 32-bit far pointer (

fp

). The

offset

, which is the least-significant word of the

pointer, is extracted by converting the pointer to

unsigned

. This discards the upper 16-bit of the

pointer, leaving the segment value. The

segment

is extracted by interpreting (casting) the pointer as

an

unsigned long

(32-bit) integer, shifting the result right 16 places, and then taking the least

significant word of the result. In this way, the

offset

and

segment

are extracted from the 32-bit

far pointer.

Calling Protocols

If the programming language we are using does not provide functions that return the

segment

or

offset

of an object, we must write our own. The data object whose address we desire is passed as an

argument to this function. The calling protocols for that language specify just how information about
the arguments is passed to the function.

There are two popular methods of passing arguments: call-by-value and call-by-reference. Other
methods, such as call-by-name which is used in Algol 60, are possible, but are not used in common
microcomputer languages.

Call-By-Value

In call-by-value, which is the only method used by C, the actual arguments are copied, and these copies
are passed to the subprogram. If the address of a variable is needed by the subprogram then that
address must be explicitly passed to the subprogram. For example:

int i; Declare and integer variable i.
i=5; Set i to 5
fun1(i); Call fun1 with an argument of 5.
fun2(&i); Call fun2 with an argument equal to the address of i.

Notice that if

fun1

tries to change the value of

i

, it only changes its own copy of

i

, not the calling

program’s variable. In contrast,

fun2

has the address of

i

and can get access to the calling program’s

variable and change its value. In call-by-value, the entire data element must be duplicated and passed
to the subprogram. This is not a problem for simple variables, but can be quite awkward if a large
array must be copied to be passed to the subprogram. Large data structures are rarely passed using
call-by-value. Instead, the address of the data structure is passed in what is, in effect, call-by-reference.

Call-By-Reference

Call-by-reference is the most common form of argument passing in languages other than C. In call-by-
reference, the address of the argument is passed to the subprogram. The size of this address may be 16
or 32 bits depending on the language and its memory model.