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?