----- Original Message ----- From: "Nicholas Clark" <[EMAIL PROTECTED]> To: "Brian Lee Ray" <[EMAIL PROTECTED]> Cc: "Josh Wilmes" <[EMAIL PROTECTED]>; <[EMAIL PROTECTED]> Sent: Saturday, February 23, 2002 5:32 AM Subject: Re: [PATCH] Bowing to necessity (was Re: [PATCH]Macro bulletproofing )
> On Sat, Feb 23, 2002 at 03:21:08AM -0600, Brian Lee Ray wrote: > > > > From: "Josh Wilmes" <[EMAIL PROTECTED]> > > > > Using NULL where a function pointer is expected is considered an error by > > > tcc, and a mandatory warning by lcc. It is my understanding that > > conversion > > > between data pointers and function pointers is forbidden under ANSI C89. > > > The relevant excerpt: > > Using NULL in this way is perfectly conforming, as it is > > expressly allowed by the standard in 6.2.2.3: > > > > =================== > > An integral constant expression with the value 0, or such an > > expression cast to type void *, is called a null pointer > > constant. If a null pointer constant is assigned to or compared > > for equality to a pointer, the constant is converted to a > > pointer of that type. Such a pointer, called a null pointer, is > > guaranteed to compare unequal to a pointer to any object or > > function. > > > > Two null pointers, converted through possibly different > > sequences of casts to pointer types, shall compare equal. > > ==================== > > Still, if tcc won't take it, there's no sense in whining about it. This > > should fix it: > > Function pointers are not data pointers. > > [And thinking about it, that excerpt doesn't say that. I hope its context did, > else I'd accuse the standard of being unclear] I don't see the words "data pointer" anywhere in the excerpt, and I didn't mean to imply that object pointers were compatible with function pointers. They aren't. However, a null pointer constant, expressed as either 0 or (void*)0 (and the definition of NULL must be one of the above), can be safely compared with or assigned to either a function pointer or a data pointer. Consider the following: void *v=NULL; typedef void(*fptr)(void); fptr f; 1:f=v; /*invalid: assignment of a void pointer to a function pointer*/ 2:f=0;f=NULL;f=(void*)0; /*all valid: assignment of a null pointer *constant to a function pointer*/ 3:v=f; /*invalid: assignment of a function pointer to a void pointer*/ 4:f==0;/*valid:comparison of a function pointer to a null pointer constant*/ 5:f==(void*)0;/*valid:comparison of a function pointer to a null pointer constant*/ 6:f==NULL;/*valid:comparison of a function pointer to a null pointer constant*/ 7:f==(fptr)v;/*must compile, however, unless both f and v are null pointers, *the result is undefined. I would expect a warning for this, as *it is a really stupid thing to do. after all, if you know that *f and v are both null pointers, the result will hardly be surprising*/ > There is some-or-other rather old Cray architecture where they are > sufficiently different that casting a function pointer to (void *) and then > back to a function pointer was enough to garble the function pointer. > [This was a perl5 bug report from 2 or 3 years ago. It was something to do > with how source filters were stashing a function pointer in an unused bit of > an IO structure, IIRC. It got fixed, with a union, IIRC] that's a case of 1: and 3: above. that's a valid argument for the definition of funcptr_t. however, since 2: and 6: are both valid, the following: #define NULLfunc NULL will perforce produce correct code on any conforming implementation. > Function pointers are not data pointers, compilers are allowed to warn. Yes, a compiler can warn about anything at any time according to the ANSI standard. However, for a strictly conforming program, it must produce an executable image which produces the expected output, therefore it is my contention that if the following program: -----begin test.c------ #include <stdio.h> int main(void) { void(*f)(void); f=NULL; if(f==NULL) puts("skippy"); return 0; } ------end test.c------- does not both compile and place the string "skippy" on stdout (followed by a newline) on tcc, then tcc is not a conforming C implementation. > [Actually, shouldn't conformant compilers always issue a diagnostic, as > you're doing something not allowed by the standard] There are surprisingly few cases where a diagnostic is required, mainly syntax errors. not of the above require a diagnostic, but nice compilers give diagnostics for things which aren't requried to produce them but which are still wrong. thus, lcc is well within it's rights to output a warning, but in my opinion, outputing a diagnostic for well defined and innocuous code (such as 2,4,5 and 6 above) is a mistake. it might just as well complain about "warning: value 0 returned from main" or "warning: integer initialized to 666. you're going to hell" > > > It seems that your mailer or something on the way has "helpfully" wrapped all > the lines in your patch. Don't you just love them? yeah, i've reprimanded it :). should I resend my first patch with the part in question removed since there's disagreement about it? brian.