wei@tiger.Princeton.EDU (P Wei) (09/11/87)
If p is declared as : struct x { int (*p)(); }; Now I want to initialize a variable y which is a structure x. struct x y = { NULLFUNC }; The question is what should I put into the #define NULLFUNC .... ? (I am using Microsoft C 4.0). Thanks for your help. HP Wei princeton!tiger!wei
guy@sun.uucp (Guy Harris) (09/11/87)
> If p is declared as : > struct x > { int (*p)(); }; > Now I want to initialize a variable y which is a structure x. > struct x y = { NULLFUNC }; > The question is what should I put into the #define NULLFUNC .... ? > (I am using Microsoft C 4.0). Thanks for your help. Unless Microsoft C 4.0 is badly broken, "#define NULLFUNC 0" should suffice; the compiler knows enough to coerce the "0" to a pointer of the appropriate type, and should do so in this context if it claims to implement C. NULL should also suffice, if it is defined as 0 or (sigh) 0L. If you want to pass a null pointer of the same type as the member of "x" to a function, and there is no prototype for that function in scope, you have to use a cast, as the compiler *doesn't* know enough to coerce "0" to a pointer of the appropriate type in that context. In that case, the properly-cast pointer is "(int (*)())0". -- Guy Harris {ihnp4, decvax, seismo, decwrl, ...}!sun!guy guy@sun.com (or guy@sun.arpa)
platt@emory.UUCP (09/12/87)
In article <27742@sun.uucp> guy@sun.uucp (Guy Harris) writes: >> If p is declared as : >> struct x >> { int (*p)(); }; >> Now I want to initialize a variable y which is a structure x. >> struct x y = { NULLFUNC }; >> The question is what should I put into the #define NULLFUNC .... ? >> (I am using Microsoft C 4.0). Thanks for your help. > >Unless Microsoft C 4.0 is badly broken, "#define NULLFUNC 0" should suffice; >the compiler knows enough to coerce the "0" to a pointer of the appropriate >type, and should do so in this context if it claims to implement C. NULL >should also suffice, if it is defined as 0 or (sigh) 0L. >-- > Guy Harris > {ihnp4, decvax, seismo, decwrl, ...}!sun!guy > guy@sun.com (or guy@sun.arpa) Actually, depending on the model (the IBM machines have a segmented addressing scheme), NULL is defined as 0 if the memory is in small or medium models, and is defined as 0L in compact and large models. Since a module may need to be compiled several ways, rather than checking the compile flags in the preprocessor, it's easiest to just define it as #define NULLFUNC NULL, and including either <stdio.h> or <stdlib.h> (either having NULL defined) before the other define. As far as the function is concerned, it doesn't care what kind of pointer is passed to it; it just passes an address. The declaration in the function where the routine is passed defines what the function is expected to do (whether the address is to be read/write, or called). Dan
guy@sun.uucp (Guy Harris) (09/13/87)
> Actually, depending on the model (the IBM machines have a segmented > addressing scheme), NULL is defined as 0 if the memory is in small or > medium models, and is defined as 0L in compact and large models. > Since a module may need to be compiled several ways, The model in which the module is compiled is *completely irrelevant* in this case, unless the compiler is broken. The compiler is required to coerce 0 (yes, a 16-bit 0) into a large-model function pointer in a context where this is called for by the language specification; an initialization counts as such a context. -- Guy Harris {ihnp4, decvax, seismo, decwrl, ...}!sun!guy guy@sun.com (or guy@sun.arpa)
greg@utcsri.UUCP (09/13/87)
In article <2236@emory.uucp> platt@emory.UUCP (Dan Platt) writes: >In article <27742@sun.uucp> guy@sun.uucp (Guy Harris) writes: >>> If p is declared as : >>> struct x >>> { int (*p)(); }; >>> Now I want to initialize a variable y which is a structure x. >>> struct x y = { NULLFUNC }; >>> The question is what should I put into the #define NhULLFUNC .... ? >>> (I am using Microsoft C 4.0). Thanks for your help.# >> >>Unless Microsoft C 4.0 is badly broken, "#define NULLFUNC 0" should suffice; >>the compiler knows enough to coerce the "0" to a pointer of the appropriate >>type, and should do so in this context if it claims to implement C. NULL >>should also suffice, if it is defined as 0 or (sigh) 0L. >>-- >> Guy Harris > >Actually, depending on the model (the IBM machines have a segmented >addressing scheme), NULL is defined as 0 if the memory is in small or >medium models, and is defined as 0L in compact and large models. Unfortunately for this 0L rubbish, function pointers differ in size from data pointers in compact and medium models. Thus it trips over its own feet, and is guaranteed to give you the wrong result for say, function_expecting_possibly_null_function_pointer( NULL ); >Since a module may need to be compiled several ways, rather than >checking the compile flags in the preprocessor, it's easiest to >just define it as #define NULLFUNC NULL, and including either ><stdio.h> or <stdlib.h> (either having NULL defined) before the other >define. ( you don't need NULL defined when you #define SOMETHING NULL, by the way). It's best to use 0 and then cast that where appropriate (i.e. in function call parameters). Writing code that compiles under various memory muddles is really no different from writing code that compiles for various machines. We got along fine with #define NULL 0 for all kinds of machines. If a function prototype is available, the cast for a NULL function parameter is unnecessary, but I leave them in, at least until I feel I will always be able to get an ANSI compiler. I find it immensely useful to make the Turbo C compiler warn me if a function call is made with no prototype. I wish it could also warn me if the prototype is causing a cast that would not be made without the prototype ( as in Root2 = sqrt(2), which works with a prototype but not without ). > >As far as the function is concerned, it doesn't care what kind of >pointer is passed to it; it just passes an address. The declaration >in the function where the routine is passed defines what the >function is expected to do (whether the address is to be read/write, or >called). > >Dan Pagan tripe. A pointer is more than just an address (and an 'address' may well be more than 'just an address'.) Firstly you can't read or write through a function pointer, and you can't call through a data pointer. The two are effectively in separate spaces. The pragmatisms of C allow you declare a function as expecting an (int *) and then pass that function a function pointer, but then you are just being very Wrong. -- ---------------------------------------------------------------------- Greg Smith University of Toronto UUCP: ..utzoo!utcsri!greg Have vAX, will hack...
chris@mimsy.UUCP (Chris Torek) (09/14/87)
In article <2236@emory.uucp> platt@emory.uucp (Dan Platt) writes: >Actually, depending on the model (the IBM machines have a segmented >addressing scheme), NULL is defined as 0 if the memory is in small or >medium models, and is defined as 0L in compact and large models. This is a bogosity intended to make broken code work. It is unnecessary and potentially confusing. >As far as the function is concerned, it doesn't care what kind of >pointer is passed to it; it just passes an address. Here is the essence of the confusion. This is *not* *true*. Despite the relative weakness of its typing, C is a typed language. Functions do not `just pass addresses' to other functions; functions pass `pointer to <object>'s, such as `pointer to function returning int'. In small models, IBM PC pointers-to-functions-returning-int occupy 16 bits; in large models, these pointers occupy 32 bits. That `0' and `0L' happen to exactly correspond to those 16 and 32 bit pointer-to-nil-function-returning-int values is what might be called an accident of design. If you write type-correct code in the first place, you will not depend upon this carefully engineered accident, and hence will not be burned when a different C implementation cannot do this for you. [We used to hear `all the world's a Vax'; is it now to be `all the world is PC compatible'?] -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
devine@vianet.UUCP (Bob Devine) (09/15/87)
In article <2236@emory.uucp>, platt@emory.uucp (Dan Platt) writes: > Actually, depending on the model (the IBM machines have a segmented > addressing scheme), NULL is defined as 0 if the memory is in small or > medium models, and is defined as 0L in compact and large models. > Since a module may need to be compiled several ways, rather than > checking the compile flags in the preprocessor, it's easiest to > just define it as #define NULLFUNC NULL, and including either > <stdio.h> or <stdlib.h> (either having NULL defined) before the other > define. This is not right. You are confusing the NULL defined for *data* pointers with *code* pointers. The silly memory models can be shown as a 2-by-2 matrix : # of code segments one multiple +------------+------------+ one | SMALL | MEDIUM | # of data | 16bit code | 32bit code | | 16bit data | 16bit data | segments +------------+------------+ mult. | "un-named" | LARGE | | 16bit code | 32bit code | | 32bit data | 32bit data | +------------+------------+ So, using NULL will only give one column of the matrix. Let the compiler do the appropriate assignment. Or, if all functions are the same, you can use a define like: #define NULLFUNC (void(*)())0 Bob Devine [ Note that MSC does not name the commonly called "compact" variation.]
gwyn@brl-smoke.ARPA (Doug Gwyn ) (09/21/87)
#define NULL 0 /* universally correct */ Just don't attempt to pass this as a parameter to a function without supplying the proper cast. func( stuff, (int (*)())NULL ); /* for example */ If you make extensive usage of such parameters, then it might save some typing to define shorthand such as #define NULL_DIRENTP ((struct dirent *)0) This would be particularly useful if the type involved might change in a future revision of the code. Ignore all babble about defining NULL as 0L etc.