• Re: type of decimal constants in msvc

    From Tim Rentsch@tr.17687@z991.linuxsc.com to comp.lang.c on Mon Dec 15 08:06:02 2025
    From Newsgroup: comp.lang.c

    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    Thiago Adams <thiago.adams@gmail.com> writes:

    The type used by MSVC compiler seems not follow the C standard.

    I choose the number 2147483648 that is the next number after max
    signed i32.

    I was expecting "signed long long" (the next signed type) but MSVC
    instead uses unsigned long (that is 32 bits)


    #define is_type(T, E) _Generic(E, T : 1 , default:0 )

    static_assert(is_type(unsigned long, 2147483648));

    int main(){}

    https://godbolt.org/z/EqKWroecj


    The the standard says
    "The type of an integer constant is the first of the
    corresponding list in which its value can be represented."

    No suffix: The potential types, in order, are int, long int, and
    long long int.

    Yes, that appears to be a bug.

    I tried an example myself with Visual Studio 2022. By default, it
    gives 2147483648 a type of unsigned long.

    The default configuration is "/std:c17". I thought it might be an "extension" that I can disable with "/Za", but astonishingly that
    produces a fatal error:

    error D8016: '/Za' and '/std:c17' command-line options are
    incompatible

    *Maybe* there's some combination of options that will persuade it to
    behave correctly.

    So I think when "cloning" MSVC I need to not follow the standard.

    I suppose, but it depends on why you want to clone MSVC and whether
    you need to replicate its bugs.

    I don't know whether this bug has been reported to Microsoft. If
    not, it should be.

    In GCC the type is long (that is 64 bits)

    https://godbolt.org/z/eTKE19r8K

    On targets with 32-bit long, it should be long long.

    It might be the case that the behavior observed is a consequence of
    Microsoft never fully embracing C99. Under C90 rules, the type of
    2147483648 (assuming 32-bit longs and unsigned longs) would indeed
    be unsigned long.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Thiago Adams@thiago.adams@gmail.com to comp.lang.c on Mon Dec 15 14:03:42 2025
    From Newsgroup: comp.lang.c

    On 12/15/2025 1:06 PM, Tim Rentsch wrote:
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    Thiago Adams <thiago.adams@gmail.com> writes:

    The type used by MSVC compiler seems not follow the C standard.

    I choose the number 2147483648 that is the next number after max
    signed i32.

    I was expecting "signed long long" (the next signed type) but MSVC
    instead uses unsigned long (that is 32 bits)


    #define is_type(T, E) _Generic(E, T : 1 , default:0 )

    static_assert(is_type(unsigned long, 2147483648));

    int main(){}

    https://godbolt.org/z/EqKWroecj


    The the standard says
    "The type of an integer constant is the first of the
    corresponding list in which its value can be represented."

    No suffix: The potential types, in order, are int, long int, and
    long long int.

    Yes, that appears to be a bug.

    I tried an example myself with Visual Studio 2022. By default, it
    gives 2147483648 a type of unsigned long.

    The default configuration is "/std:c17". I thought it might be an
    "extension" that I can disable with "/Za", but astonishingly that
    produces a fatal error:

    error D8016: '/Za' and '/std:c17' command-line options are
    incompatible

    *Maybe* there's some combination of options that will persuade it to
    behave correctly.

    So I think when "cloning" MSVC I need to not follow the standard.

    I suppose, but it depends on why you want to clone MSVC and whether
    you need to replicate its bugs.

    I don't know whether this bug has been reported to Microsoft. If
    not, it should be.

    In GCC the type is long (that is 64 bits)

    https://godbolt.org/z/eTKE19r8K

    On targets with 32-bit long, it should be long long.

    It might be the case that the behavior observed is a consequence of
    Microsoft never fully embracing C99. Under C90 rules, the type of
    2147483648 (assuming 32-bit longs and unsigned longs) would indeed
    be unsigned long.


    My guess they were doing this before 64bit integers were introduced.
    Then, after 64 bits, the kept this to avoid breaking changes.

    Today, when the number is not represented in a signed 64 bits, in theory
    it should use 128 signed, but it uses 64 unsigned instead and we have a warning.

    For instance:

    9223372036854775808

    warning: integer literal is too large to be represented in a signed
    integer type, interpreting as unsigned [-Wimplicitly-unsigned-literal]

    What is interesting that C code is not portable. (nothing new, just saying)

    Thiago




    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Keith Thompson@Keith.S.Thompson+u@gmail.com to comp.lang.c on Mon Dec 15 14:14:43 2025
    From Newsgroup: comp.lang.c

    Thiago Adams <thiago.adams@gmail.com> writes:
    [...]
    Today, when the number is not represented in a signed 64 bits, in
    theory it should use 128 signed, but it uses 64 unsigned instead and
    we have a warning.

    In C99 and later, an unsuffixed integer constant is *never* of unsigned
    type.

    For instance:

    9223372036854775808

    That's 2**63, likely equal to LLONG_MAX+1.

    warning: integer literal is too large to be represented in a signed
    integer type, interpreting as unsigned [-Wimplicitly-unsigned-literal]

    What is interesting that C code is not portable. (nothing new, just saying)

    The error message is incorrect, a bug that's been reported against gcc :

    https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96788

    But I think that error message is from clang (gcc's message refers to
    "integer constant", clang's to "integer literal").

    The type of an unsuffixed integer constant is the first of (int,
    long int, long long int) in which its value can be represented.
    If it exceeds LLONG_MAX, it *may* be of an extended integer type;
    neither gcc nor clang supports extended integer types. Failing that,
    "the integer constant has no type", which violates a constraint:
    "Each constant shall have a type and the value of a constant shall
    be in the range of representable values for its type."

    With 64-bit gcc, 9223372036854775808 is of type __int128 -- which (a)
    is not an unsigned type, as stated by the incorrect warning message,
    and (b) is *not* an extended integer type. (gcc does produce a
    diagnostic, which is all that's required for a constraint violation,
    but it's certainly a bug.)

    With 64-bit clang, 9223372036854775808 is of type unsigned long long,
    which is incorrect but at least consistent with the warning message.

    #include <stdio.h>
    int main(void) {
    printf("9223372036854775808 is of type %s\n",
    _Generic(9223372036854775808,
    int: "int",
    unsigned int: "unsigned int",
    long: "long",
    unsigned long: "unsigned long",
    long long: "long long",
    unsigned long long: "unsigned long long",
    #ifdef __GNUC__
    __int128: "__int128",
    unsigned __int128: "unsigned __int128",
    #endif
    default: "<unknown>"
    ));
    }
    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Thiago Adams@thiago.adams@gmail.com to comp.lang.c on Fri Dec 19 08:43:54 2025
    From Newsgroup: comp.lang.c

    Em 02/09/2025 17:10, Thiago Adams escreveu:
    The type used by MSVC compiler seems not follow the C standard.

    I choose the number 2147483648 that is the next number after max signed
    i32.


    For some reason GCC and clang have a warning (integer literal is too
    large to be represented in a signed integer type) only for decimal form.

    We have a warning for 18408377700990114895 but not for the same number written as hex 0xff77b1fcbebcdc4f.


    int main(){
    static_assert(18408377700990114895 == 0xff77b1fcbebcdc4f);
    }

    https://godbolt.org/z/PPYErfrTP

    But I don't think hex is especial in this case.

    unsigned long long u[] = {18408377700990114895 , 0xff77b1fcbebcdc4f};

    I think a suffix ULL maybe useful in this case.

    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Keith Thompson@Keith.S.Thompson+u@gmail.com to comp.lang.c on Fri Dec 19 04:15:46 2025
    From Newsgroup: comp.lang.c

    Thiago Adams <thiago.adams@gmail.com> writes:
    Em 02/09/2025 17:10, Thiago Adams escreveu:
    The type used by MSVC compiler seems not follow the C standard.
    I choose the number 2147483648 that is the next number after max signed i32.

    For some reason GCC and clang have a warning (integer literal is too
    large to be represented in a signed integer type) only for decimal
    form.

    We have a warning for 18408377700990114895 but not for the same number written as hex 0xff77b1fcbebcdc4f.

    Yes.

    gcc's warning for 18408377700990114895 (which is slightly smaller
    than 2**64) is "integer constant is so large that it is unsigned".
    This is *incorrect* (and I think it's been reported as a bug), but
    the incorrect wording of the warning is not a conformance issue.

    (I'm assuming long long is 64 bits. It can be wider, at least
    theoretically.)

    In C99 and later, an unsuffixed decimal constant is always of some
    signed type, the smallest of int, long, and long long in which it
    fits -- or of an extended integer type, but gcc doesn't have those.
    Since 18408377700990114895 exceeds LLONG_MAX, it has no type, and
    is a constraint violation. (In C90, the list was int, long, unsigned
    long, which is the source of the wording of the warning message.)

    An unsuffixed hex constant can be of type int, unsigned int, long
    int, unsigned long int, long long int, or unsigned long long int
    (or an extended integer type). Since 0xff77b1fcbebcdc4f is greater
    than LLONG_MAX and less than (or equal to) ULLONG_MAX, it's of type
    unsigned long long int, and no diagostic is needed.

    [...]

    But I don't think hex is especial in this case.

    It is.

    unsigned long long u[] = {18408377700990114895 , 0xff77b1fcbebcdc4f};

    I think a suffix ULL maybe useful in this case.

    This:

    unsigned long long u[] = {18408377700990114895ULL, 0xff77b1fcbebcdc4fULL};

    is valid. The ULL suffix on the hex constant isn't strictly
    necessary, but it certainly doesn't hurt. (If unsigned long long is,
    say, 128 bits and long is 64 bits, an unsuffixed 18408377700990114895
    will be of type long long, and an unsuffixed 0xff77b1fcbebcdc4f
    will be of type unsigned long, both of which will be implicitly
    converted to unsigned long long.)

    For that matter, just a "U" suffix would suffice. A decimal constant
    with a "U" suffix is of type unsigned int, unsigned long int, or
    unsigned long long int.

    See N1570 6.4.4.1 or N3220 6.4.4.2.
    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Thiago Adams@thiago.adams@gmail.com to comp.lang.c on Fri Dec 19 09:49:24 2025
    From Newsgroup: comp.lang.c

    Em 19/12/2025 09:15, Keith Thompson escreveu:
    Thiago Adams <thiago.adams@gmail.com> writes:
    Em 02/09/2025 17:10, Thiago Adams escreveu:
    The type used by MSVC compiler seems not follow the C standard.
    I choose the number 2147483648 that is the next number after max signed i32.

    For some reason GCC and clang have a warning (integer literal is too
    large to be represented in a signed integer type) only for decimal
    form.

    We have a warning for 18408377700990114895 but not for the same number
    written as hex 0xff77b1fcbebcdc4f.

    Yes.

    gcc's warning for 18408377700990114895 (which is slightly smaller
    than 2**64) is "integer constant is so large that it is unsigned".
    This is *incorrect* (and I think it's been reported as a bug), but
    the incorrect wording of the warning is not a conformance issue.


    I am not understating why do you think this is a bug?
    Because it should not compile?

    (I'm assuming long long is 64 bits. It can be wider, at least theoretically.)

    In C99 and later, an unsuffixed decimal constant is always of some
    signed type, the smallest of int, long, and long long in which it
    fits -- or of an extended integer type, but gcc doesn't have those.
    Since 18408377700990114895 exceeds LLONG_MAX, it has no type, and
    is a constraint violation. (In C90, the list was int, long, unsigned
    long, which is the source of the wording of the warning message.)

    An unsuffixed hex constant can be of type int, unsigned int, long
    int, unsigned long int, long long int, or unsigned long long int
    (or an extended integer type). Since 0xff77b1fcbebcdc4f is greater
    than LLONG_MAX and less than (or equal to) ULLONG_MAX, it's of type
    unsigned long long int, and no diagostic is needed.

    [...]

    But I don't think hex is especial in this case.

    It is.

    unsigned long long u[] = {18408377700990114895 , 0xff77b1fcbebcdc4f};

    I think a suffix ULL maybe useful in this case.

    This:

    unsigned long long u[] = {18408377700990114895ULL, 0xff77b1fcbebcdc4fULL};

    is valid. The ULL suffix on the hex constant isn't strictly
    necessary, but it certainly doesn't hurt. (If unsigned long long is,
    say, 128 bits and long is 64 bits, an unsuffixed 18408377700990114895
    will be of type long long, and an unsuffixed 0xff77b1fcbebcdc4f
    will be of type unsigned long, both of which will be implicitly
    converted to unsigned long long.)

    For that matter, just a "U" suffix would suffice. A decimal constant
    with a "U" suffix is of type unsigned int, unsigned long int, or
    unsigned long long int.

    See N1570 6.4.4.1 or N3220 6.4.4.2.


    Thanks...yes I can see a table on n3220.


    "The type of an integer constant is the first of the corresponding list
    in which its value can be represented"

    Octal, Hexadecimal or Binary Constant

    int
    unsigned int

    long int
    unsigned long int

    long long int
    unsigned long long int

    I was something that I was not expecting but but the specification is
    very clear.




    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Keith Thompson@Keith.S.Thompson+u@gmail.com to comp.lang.c on Fri Dec 19 12:26:45 2025
    From Newsgroup: comp.lang.c

    Thiago Adams <thiago.adams@gmail.com> writes:
    Em 19/12/2025 09:15, Keith Thompson escreveu:
    [...]
    gcc's warning for 18408377700990114895 (which is slightly smaller
    than 2**64) is "integer constant is so large that it is unsigned".
    This is *incorrect* (and I think it's been reported as a bug), but
    the incorrect wording of the warning is not a conformance issue.

    I am not understating why do you think this is a bug?
    Because it should not compile?

    No, because the message is factually incorrect. The integer constant 18408377700990114895 is not of any unsigned type.

    Diagnosing it is correct (since 18408377700990114895 > LLONG_MAX),
    but the message is incorrect.

    The bug report is <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96788>.

    [...]
    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Tim Rentsch@tr.17687@z991.linuxsc.com to comp.lang.c on Mon Dec 22 05:05:04 2025
    From Newsgroup: comp.lang.c

    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

    Thiago Adams <thiago.adams@gmail.com> writes:

    Em 19/12/2025 09:15, Keith Thompson escreveu:

    [...]

    gcc's warning for 18408377700990114895 (which is slightly smaller
    than 2**64) is "integer constant is so large that it is unsigned".
    This is *incorrect* (and I think it's been reported as a bug), but
    the incorrect wording of the warning is not a conformance issue.

    I am not understating why do you think this is a bug?
    Because it should not compile?

    No, because the message is factually incorrect.

    No, it isn't. The message might be misleading but it isn't wrong.

    The integer constant 18408377700990114895 is not of any unsigned type.

    The message doesn't say the constant has an unsigned type. It says
    only that the constant is unsigned.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Keith Thompson@Keith.S.Thompson+u@gmail.com to comp.lang.c on Mon Dec 22 12:01:48 2025
    From Newsgroup: comp.lang.c

    Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
    Thiago Adams <thiago.adams@gmail.com> writes:
    Em 19/12/2025 09:15, Keith Thompson escreveu:
    [...]

    gcc's warning for 18408377700990114895 (which is slightly smaller
    than 2**64) is "integer constant is so large that it is unsigned".
    This is *incorrect* (and I think it's been reported as a bug), but
    the incorrect wording of the warning is not a conformance issue.

    I am not understating why do you think this is a bug?
    Because it should not compile?

    No, because the message is factually incorrect.

    No, it isn't. The message might be misleading but it isn't wrong.

    The integer constant 18408377700990114895 is not of any unsigned type.

    The message doesn't say the constant has an unsigned type. It says
    only that the constant is unsigned.

    What distinction are you making?

    All integer constants are "unsigned" in the sense that they don't
    include a sign. -1 is an expression, not a constant. That's not
    what the message means.

    I see no reasonable interpretation of "integer constant is so
    large that it is unsigned" other than that it's of an unsigned type
    because it's too large.

    The message correctly reflects the C90 semantics, where a
    sufficiently large unsuffixed decimal integer constant is of type
    unsigned long. But in C99 and later, an unsuffixed decimal integer
    constant is never of any unsigned type.
    --
    Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
    void Void(void) { Void(); } /* The recursive call of the void */
    --- Synchronet 3.21a-Linux NewsLink 1.2