Path: csiph.com!eternal-september.org!feeder.eternal-september.org!nntp.eternal-september.org!.POSTED!not-for-mail From: Tim Rentsch Newsgroups: comp.lang.c Subject: Re: Prioritize Performance over Correctness Date: Mon, 24 Aug 2026 10:15:53 -0700 Organization: A noiseless patient Spider Lines: 198 Message-ID: <86fr03xwvq.fsf@linuxsc.com> References: <113ovuj$23t9c$1@dont-email.me> <114f9up$1mm0c$1@dont-email.me> <114ge0v$24ndu$2@dont-email.me> <114h1v7$2b0po$2@dont-email.me> <114h24r$9nm$1@reader1.panix.com> <114h26m$2b0po$3@dont-email.me> <114kain$3erqe$1@dont-email.me> <114rbq0$1op2s$1@dont-email.me> <114rd9b$1o8k3$2@kst.eternal-september.org> <86wltjzli9.fsf@linuxsc.com> <116a2es$gkc1$1@kst.eternal-september.org> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Injection-Date: Mon, 24 Aug 2026 17:15:56 +0000 (UTC) Injection-Info: dont-email.me; logging-data="3227379"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX19Bp9Ui5nouiY3svvbSrsXZP0dgFGb0uDY="; posting-host="9735fe02a9db7cd6865f5c5d07f214ae" User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux) Cancel-Lock: sha1:DVQS7WCgo0j2ih10rLbKjl31QzQ= sha1:GAVrLD2HISx3ml9KQ4+OD7L262E= sha256:iT9HyfFqMy+LUr7sEekDEEcFu/8tUJjmWgiQhRTqE2M= sha1:DHlq1km6tcaXqpIB55j5885X9NY= sha256:fkQzvAQ6D+rbjemDhgSxehPkYD3Sit0vzsM65bxXb+k= Xref: csiph.com comp.lang.c:401464 Keith Thompson writes: > Tim Rentsch writes: > >> Keith Thompson writes: >> >>> The standard doesn't say that function pointers can be converted to >>> object pointer types or vice versa -- no does it say that they can't. >>> My conclusion is that the behavior of such a conversion is undefined >>> by omission. >> >> This understanding isn't right, or at best incomplete. > > [snip] > > I disagree. Well, let's explore that. Here is the context that was snipped: > Keith Thompson writes: > >> The standard doesn't say that function pointers can be converted to >> object pointer types or vice versa -- no does it say that they can't. >> My conclusion is that the behavior of such a conversion is undefined >> by omission. > > This understanding isn't right, or at best incomplete. A statement > like "a pointer to an object type may be converted to a pointer to a > different object type" is not a definition of behavior but a statement > about what is part of the C language. The C standard lists all cases > where a conversion may be done to or from a pointer type; for > pointers, any case where there is not an explicit allowance is not > part of the C language. Because there is no explicit allowance, an > implementation is free to reject any translation unit that calls for > such a conversion. Because there is no requirement for a diagnostic, > an implementation is free to accept programs that do call for such a > conversion. Certainly if an implementation accepts a program that > converts an object pointer to a function pointer, or vice versa, then > the behavior of any such construct is undefined; but implementations > are not obliged to accept any program whose source indicates any such > conversion. We start with a simple program: // file integer.c int main( void ){ return 0; } void * integer_to_pointer( long x ){ return (void*) x; } There is no problem with this program. It is in fact strictly conforming. The cast to (void*) would have potential undefined behavior if it were executed but since the function is never called of course that doesn't happen. We can compile and execute it: gcc -std=c99 -pedantic -o integer-gcc integer.c ./integer-gcc ; echo $? 0 clang -std=c99 -pedantic -o integer-clang integer.c ./integer-clang ; echo $? 0 To continue the exploration, we consider a slightly different program: // file floating.c int main( void ){ return 0; } void * floating_to_pointer( double x ){ return (void*) x; } The only difference (not counting the change in function name) between floating.c and integer.c is the type of the function parameter, which has a real floating type rather than an integer type. How does that difference affect program semantics? An easy way to investigate that question is to try compiling and running it (one long line of output was wrapped): gcc -std=c99 -pedantic -o floating-gcc floating.c floating.c: In function 'floating_to_pointer': floating.c:10:4: error: cannot convert to a pointer type return (void*) x; ^~~~~~ {no executable was produced} clang -std=c99 -pedantic -o floating-clang floating.c floating.c:10:20: error: operand of type 'double' cannot be cast {wrapped here} to a pointer type return (void*) x; ^ 1 error generated. {no executable was produced} Both gcc and clang consider floating.c to have a fatal error, caused by trying to convert the double parameter x to (void*). The reasoning underlying this decision is fairly straightforward. The C standard says an integer may be converted to any pointer type; in contrast, the standard does not say floating values may be converted to any kind of pointer type. Because the standard does not include any such provision, floating.c is attempting to use a feature not specified in the C standard. Because floating.c is trying to use a feature not specified, it is not strictly conforming. Because floating.c is not strictly conforming, the standard does not require it to be accepted. Because there is no requirement that floating.c be accepted, both gcc and clang choose to give an error and reject it. I don't see any other chain of reasoning that would allow these compilers to summarily dismiss floating.c. So I think we can feel fairly confident that the reasoning above explains the rationale for these compilers to not allow floating.c. Now let's look at converting a pointer-to-function to an object pointer type. Here is a program to help investigate that: // file pointers.c int main( void ){ return 0; } void * function_pointer_to_object_pointer( void x(void) ){ return (void*) x; } The relationship between floating types and pointer types is analogous to the relationship beween function pointer types and object pointer types: the C standard explicitly allows some conversions of these types, but the standard does not say that a function pointer type may be converted to an object pointer type, just as it does not say that a floating type may be converted to a pointer type. What may we expect for the semantics of pointers.c? As before, we try compiling (two long lines of output wrapped): gcc -std=c99 -pedantic -o pointers-gcc-warnings pointers.c pointers.c: In function 'function_pointer_to_object_pointer': pointers.c:10:12: warning: ISO C forbids conversion of function pointer {wrapped here} to object pointer type [-Wpedantic] return (void*) x; ^ ./pointers-gcc-warnings ; echo $? 0 gcc -std=c99 -pedantic-errors -o pointers-gcc-errors pointers.c pointers.c: In function 'function_pointer_to_object_pointer': pointers.c:10:12: error: ISO C forbids conversion of function pointer {wrapped here} to object pointer type [-Wpedantic] return (void*) x; ^ {no executable was produced} clang -std=c99 -pedantic -o pointers-clang pointers.c ./pointers-clang ; echo $? 0 (Here we have run gcc twice, first giving option -pedantic and next giving option -pedantic-errors.) The behaviors of gcc and clang are different: clang compiles pointers.c without giving any diagnostics, but gcc gives a diagnostic saying "ISO C forbids conversion of function pointer to object pointer type [-Wpedantic]", which is only a warning under -pedantic but an error under -pedantic-errors. In both cases how the compilers behave is consistent with the C standard. There is no requirement to accept pointers.c, using the same reasoning explained above, and gcc makes that choice, rejecting pointers.c when -pedantic-errors is in force. At the same time though there is no requirement /not/ to accept pointers.c, and clang chooses to accept it without complaint. (Of course diagnostics may be given whether a program is accepted or not.) Note that if converting a floating type or a function pointer type to a (void*) were only undefined behavior, and not more than that, then all of these programs would be strictly conforming, and so would have to be accepted. But that doesn't match how the compilers behave. Note also that the behaviors of gcc and clang are consistent with what I said before, which was given in the re-inserted excerpt above. Considering all that, what is your current assessment? Is it your position that your understanding of the C standard is somehow better than not only how I read it but also how it is understood by both gcc developers and clang developers? Or have you changed your views?