• Re: Prioritize Performance over Correctness

    From Tim Rentsch@3:633/10 to All on Sun Aug 16 07:59:43 2026
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    Note that the requirement for all-bits-zero to be a valid
    representation for zero in all integer types was added, without
    much fanfare, in a technical corrigendum to C99, [...]

    That's true but it wasn't at all a big leap. First it was
    already guaranteed to be true for integer types without padding
    bits. Second the only additional constraint imposed is that a
    value of 0 could have all padding bits be zeros (which likely was
    already satisfied by all existing implementations). The C89/C90
    standard doesn't use the term padding bits but they may be
    inferred from the description of binary representation for
    integer values ("pure binary numeration system").

    --- PyGate Linux v1.5.19
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Tim Rentsch@3:633/10 to All on Fri Aug 21 05:49:34 2026
    Keith Thompson <Keith.S.Thompson+u@gmail.com> 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.

    --- PyGate Linux v1.5.19
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Keith Thompson@3:633/10 to All on Fri Aug 21 10:38:36 2026
    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
    Keith Thompson <Keith.S.Thompson+u@gmail.com> 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.

    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */

    --- PyGate Linux v1.5.19
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Scott Lurndal@3:633/10 to All on Fri Aug 21 18:25:57 2026
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
    Keith Thompson <Keith.S.Thompson+u@gmail.com> 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.

    Perhaps Tim was being humorous and referring to the missing 'r'
    after the double hyphen.... I doubt it tho.

    --- PyGate Linux v1.5.19
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Tim Rentsch@3:633/10 to All on Mon Aug 24 10:15:53 2026
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:

    Keith Thompson <Keith.S.Thompson+u@gmail.com> 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 <Keith.S.Thompson+u@gmail.com> 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?

    --- PyGate Linux v1.5.19
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)