Why do implementations of “stdint.h” disagree on the definition of UINT8_C?Why does the most negative int...

4-dimensional Knight's Tour

How can I make Ubuntu run well (including with wifi) on a 32-bit machine?

Decode a variable-length quantity

Does the United States guarantee any unique freedoms?

Was there ever a difference between 'volo' and 'volo'?

Secure my password from unsafe servers

Can ads on a page read my password?

Short story about a teenager who has his brain replaced with a microchip (Psychological Horror)

How does The Fools Guild make its money?

Are any British or English Acts of Parliament still in force in the United States?

Is it allowed and safe to carry a passenger / non-pilot in the front seat of a small general aviation airplane?

Why are the inside diameters of some pipe larger than the stated size?

How to avoid ci-driven development..?

Why is there a need to prevent a racist, sexist, or otherwise bigoted vendor from discriminating who they sell to?

Half-rock- half-forest-gnome

Do other countries guarantee freedoms that the United States does not have?

How would I as a DM create a smart phone-like spell/device my players could use?

Look mom! I made my own (Base 10) numeral system!

Validation and verification of mathematical models

sytemctl status log output

Is alignment needed after replacing upper control arms?

How is the return type of a ternary operator determined?

Does this smartphone photo show Mars just below the Sun?

In Pokémon Go, why does one of my Pikachu have an option to evolve, but another one doesn't?



Why do implementations of “stdint.h” disagree on the definition of UINT8_C?


Why does the most negative int value cause an error about ambiguous function overloads?With arrays, why is it the case that a[5] == 5[a]?The Definitive C++ Book Guide and ListWhy can templates only be implemented in the header file?What is the difference between a definition and a declaration?Why is “using namespace std;” considered bad practice?Why are elementwise additions much faster in separate loops than in a combined loop?Why is reading lines from stdin much slower in C++ than Python?Why is processing a sorted array faster than processing an unsorted array?Why Microsoft Visual Studio cannot find <stdint.h>?Why should I use a pointer rather than the object itself?






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ margin-bottom:0;
}







6















The UINT8_C macro is defined in "stdint.h", with the following specification: The macro UINTN_C(value) shall expand to an integer constant expression corresponding to the type uint_leastN_t.



In the wild, however, implementations differ:



#define UINT8_C(value) ((uint8_t) __CONCAT(value, U))  // AVR-libc
#define UINT8_C(x_) (static_cast<std::uint8_t>(x_)) // QP/C++
#define UINT8_C(c) c // GNU C Library


The first two implementations seem roughly equivalent, but the third one behaves differently: for example, the following program prints 1 with AVR-libc and QP/C++, but -1 with glibc (because right shifts on signed values propagate the sign bit).



std::cout << (UINT8_C(-1) >> 7) << std::endl; // prints -1 in glibc


The implementation of UINT16_C displays the same behavior, but not UINT32_C, because its definition includes the U suffix:



#define UINT32_C(c) c ## U


Interestingly, glibc's definition of UINT8_C changed in 2006, due to a bug report. The previous definition was #define UINT8_C(c) c ## U, but that produced incorrect output (false) on -1 < UINT8_C(0) due to integer promotion rules.



Are all three definitions correct according to the standard? Are there other differences (besides the handling of negative constants) between these three implementations?










share|improve this question






















  • 5





    In C++ you want to #include <cstdint>, not stdint.h - just saying.

    – Jesper Juhl
    8 hours ago






  • 2





    Implementations can't be controlled by the standard; the implementation can do what it likes, but is supposed to be guided by the standard. Implementations actually do their own thing. It is not hard to argue that the GNU C Library version isn't very accurate, but in a C (as opposed to C++) library, it is hard to know when it will make a difference (since almost any use of the macro will be expanded to int before anything further happens).

    – Jonathan Leffler
    8 hours ago








  • 1





    @chris That's the point: Casting -1 to an unsigned type should theoretically yield the maximum representable value of that type (and subsequently behave just fine when right-shifted).

    – Max Langhof
    8 hours ago






  • 2





    Since requirement is "expand to an integer constant expression corresponding to the type uint_leastN_t", I'd expect a cast of whatever is within as in ((uint_least8_t) (c))

    – chux
    8 hours ago






  • 1





    @MaxLanghof, My bad, I glossed over the sign mismatch of the value and UINT8_C.

    – chris
    8 hours ago


















6















The UINT8_C macro is defined in "stdint.h", with the following specification: The macro UINTN_C(value) shall expand to an integer constant expression corresponding to the type uint_leastN_t.



In the wild, however, implementations differ:



#define UINT8_C(value) ((uint8_t) __CONCAT(value, U))  // AVR-libc
#define UINT8_C(x_) (static_cast<std::uint8_t>(x_)) // QP/C++
#define UINT8_C(c) c // GNU C Library


The first two implementations seem roughly equivalent, but the third one behaves differently: for example, the following program prints 1 with AVR-libc and QP/C++, but -1 with glibc (because right shifts on signed values propagate the sign bit).



std::cout << (UINT8_C(-1) >> 7) << std::endl; // prints -1 in glibc


The implementation of UINT16_C displays the same behavior, but not UINT32_C, because its definition includes the U suffix:



#define UINT32_C(c) c ## U


Interestingly, glibc's definition of UINT8_C changed in 2006, due to a bug report. The previous definition was #define UINT8_C(c) c ## U, but that produced incorrect output (false) on -1 < UINT8_C(0) due to integer promotion rules.



Are all three definitions correct according to the standard? Are there other differences (besides the handling of negative constants) between these three implementations?










share|improve this question






















  • 5





    In C++ you want to #include <cstdint>, not stdint.h - just saying.

    – Jesper Juhl
    8 hours ago






  • 2





    Implementations can't be controlled by the standard; the implementation can do what it likes, but is supposed to be guided by the standard. Implementations actually do their own thing. It is not hard to argue that the GNU C Library version isn't very accurate, but in a C (as opposed to C++) library, it is hard to know when it will make a difference (since almost any use of the macro will be expanded to int before anything further happens).

    – Jonathan Leffler
    8 hours ago








  • 1





    @chris That's the point: Casting -1 to an unsigned type should theoretically yield the maximum representable value of that type (and subsequently behave just fine when right-shifted).

    – Max Langhof
    8 hours ago






  • 2





    Since requirement is "expand to an integer constant expression corresponding to the type uint_leastN_t", I'd expect a cast of whatever is within as in ((uint_least8_t) (c))

    – chux
    8 hours ago






  • 1





    @MaxLanghof, My bad, I glossed over the sign mismatch of the value and UINT8_C.

    – chris
    8 hours ago














6












6








6








The UINT8_C macro is defined in "stdint.h", with the following specification: The macro UINTN_C(value) shall expand to an integer constant expression corresponding to the type uint_leastN_t.



In the wild, however, implementations differ:



#define UINT8_C(value) ((uint8_t) __CONCAT(value, U))  // AVR-libc
#define UINT8_C(x_) (static_cast<std::uint8_t>(x_)) // QP/C++
#define UINT8_C(c) c // GNU C Library


The first two implementations seem roughly equivalent, but the third one behaves differently: for example, the following program prints 1 with AVR-libc and QP/C++, but -1 with glibc (because right shifts on signed values propagate the sign bit).



std::cout << (UINT8_C(-1) >> 7) << std::endl; // prints -1 in glibc


The implementation of UINT16_C displays the same behavior, but not UINT32_C, because its definition includes the U suffix:



#define UINT32_C(c) c ## U


Interestingly, glibc's definition of UINT8_C changed in 2006, due to a bug report. The previous definition was #define UINT8_C(c) c ## U, but that produced incorrect output (false) on -1 < UINT8_C(0) due to integer promotion rules.



Are all three definitions correct according to the standard? Are there other differences (besides the handling of negative constants) between these three implementations?










share|improve this question
















The UINT8_C macro is defined in "stdint.h", with the following specification: The macro UINTN_C(value) shall expand to an integer constant expression corresponding to the type uint_leastN_t.



In the wild, however, implementations differ:



#define UINT8_C(value) ((uint8_t) __CONCAT(value, U))  // AVR-libc
#define UINT8_C(x_) (static_cast<std::uint8_t>(x_)) // QP/C++
#define UINT8_C(c) c // GNU C Library


The first two implementations seem roughly equivalent, but the third one behaves differently: for example, the following program prints 1 with AVR-libc and QP/C++, but -1 with glibc (because right shifts on signed values propagate the sign bit).



std::cout << (UINT8_C(-1) >> 7) << std::endl; // prints -1 in glibc


The implementation of UINT16_C displays the same behavior, but not UINT32_C, because its definition includes the U suffix:



#define UINT32_C(c) c ## U


Interestingly, glibc's definition of UINT8_C changed in 2006, due to a bug report. The previous definition was #define UINT8_C(c) c ## U, but that produced incorrect output (false) on -1 < UINT8_C(0) due to integer promotion rules.



Are all three definitions correct according to the standard? Are there other differences (besides the handling of negative constants) between these three implementations?







c++ c standards integer-promotion stdint






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 8 hours ago









πάντα ῥεῖ

76k10 gold badges81 silver badges149 bronze badges




76k10 gold badges81 silver badges149 bronze badges










asked 8 hours ago









ClémentClément

6,56312 gold badges51 silver badges90 bronze badges




6,56312 gold badges51 silver badges90 bronze badges











  • 5





    In C++ you want to #include <cstdint>, not stdint.h - just saying.

    – Jesper Juhl
    8 hours ago






  • 2





    Implementations can't be controlled by the standard; the implementation can do what it likes, but is supposed to be guided by the standard. Implementations actually do their own thing. It is not hard to argue that the GNU C Library version isn't very accurate, but in a C (as opposed to C++) library, it is hard to know when it will make a difference (since almost any use of the macro will be expanded to int before anything further happens).

    – Jonathan Leffler
    8 hours ago








  • 1





    @chris That's the point: Casting -1 to an unsigned type should theoretically yield the maximum representable value of that type (and subsequently behave just fine when right-shifted).

    – Max Langhof
    8 hours ago






  • 2





    Since requirement is "expand to an integer constant expression corresponding to the type uint_leastN_t", I'd expect a cast of whatever is within as in ((uint_least8_t) (c))

    – chux
    8 hours ago






  • 1





    @MaxLanghof, My bad, I glossed over the sign mismatch of the value and UINT8_C.

    – chris
    8 hours ago














  • 5





    In C++ you want to #include <cstdint>, not stdint.h - just saying.

    – Jesper Juhl
    8 hours ago






  • 2





    Implementations can't be controlled by the standard; the implementation can do what it likes, but is supposed to be guided by the standard. Implementations actually do their own thing. It is not hard to argue that the GNU C Library version isn't very accurate, but in a C (as opposed to C++) library, it is hard to know when it will make a difference (since almost any use of the macro will be expanded to int before anything further happens).

    – Jonathan Leffler
    8 hours ago








  • 1





    @chris That's the point: Casting -1 to an unsigned type should theoretically yield the maximum representable value of that type (and subsequently behave just fine when right-shifted).

    – Max Langhof
    8 hours ago






  • 2





    Since requirement is "expand to an integer constant expression corresponding to the type uint_leastN_t", I'd expect a cast of whatever is within as in ((uint_least8_t) (c))

    – chux
    8 hours ago






  • 1





    @MaxLanghof, My bad, I glossed over the sign mismatch of the value and UINT8_C.

    – chris
    8 hours ago








5




5





In C++ you want to #include <cstdint>, not stdint.h - just saying.

– Jesper Juhl
8 hours ago





In C++ you want to #include <cstdint>, not stdint.h - just saying.

– Jesper Juhl
8 hours ago




2




2





Implementations can't be controlled by the standard; the implementation can do what it likes, but is supposed to be guided by the standard. Implementations actually do their own thing. It is not hard to argue that the GNU C Library version isn't very accurate, but in a C (as opposed to C++) library, it is hard to know when it will make a difference (since almost any use of the macro will be expanded to int before anything further happens).

– Jonathan Leffler
8 hours ago







Implementations can't be controlled by the standard; the implementation can do what it likes, but is supposed to be guided by the standard. Implementations actually do their own thing. It is not hard to argue that the GNU C Library version isn't very accurate, but in a C (as opposed to C++) library, it is hard to know when it will make a difference (since almost any use of the macro will be expanded to int before anything further happens).

– Jonathan Leffler
8 hours ago






1




1





@chris That's the point: Casting -1 to an unsigned type should theoretically yield the maximum representable value of that type (and subsequently behave just fine when right-shifted).

– Max Langhof
8 hours ago





@chris That's the point: Casting -1 to an unsigned type should theoretically yield the maximum representable value of that type (and subsequently behave just fine when right-shifted).

– Max Langhof
8 hours ago




2




2





Since requirement is "expand to an integer constant expression corresponding to the type uint_leastN_t", I'd expect a cast of whatever is within as in ((uint_least8_t) (c))

– chux
8 hours ago





Since requirement is "expand to an integer constant expression corresponding to the type uint_leastN_t", I'd expect a cast of whatever is within as in ((uint_least8_t) (c))

– chux
8 hours ago




1




1





@MaxLanghof, My bad, I glossed over the sign mismatch of the value and UINT8_C.

– chris
8 hours ago





@MaxLanghof, My bad, I glossed over the sign mismatch of the value and UINT8_C.

– chris
8 hours ago












3 Answers
3






active

oldest

votes


















5














If an int can represent all the values of a uint_least8_t then the GNU implementation of the UINT8_C(value) macro as #define UINT8_C(c) c conforms to the C standard.



As per C11 7.20.4 Macros for integer constants paragraph 2:




The argument in any instance of these macros shall be an unsuffixed integer constant (as defined in 6.4.4.1) with a value that does not exceed the limits for the corresponding type.




For example, if UINT_LEAST8_MAX is 255, the following usage examples are legal:




  • UINT8_C(0)

  • UINT8_C(255)

  • UINT8_C(0377)

  • UINT8_C(0xff)


But the following usage examples result in undefined behavior:





  • UINT8_C(-1) — not an integer constant as defined in 6.4.4.1


  • UINT8_C(1u) — not an unsuffixed integer constant


  • UINT8_C(256) — exceeds the limits of uint_least8_t for this implementation


The signed equivalent INT8_C(-1) is also undefined behavior for the same reasons.



If UINT_LEAST8_MAX is 255, a legal instance of UINT8_C(value) will expand to an integer constant expression and its type will be int due to integer promotions, as per paragraph 3:




Each invocation of one of these macros shall expand to an integer constant expression suitable for use in #if preprocessing directives. The type of the expression shall have the same type as would an expression of the corresponding type converted according to the integer promotions. The value of the expression shall be that of the argument.




Thus for any legal invocation of UINT8_C(value), the expansion of this to value by any implementation where an int can represent all the values of uint_least8_t is perfectly standard conforming. For any illegal invocation of UINT8_C(value) you may not get the result you were expecting due to undefined behavior.



[EDIT added for completeness] As pointed out in cpplearner's answer, the other implementations of UINT8_C(value) shown in OP's question are invalid because they expand to expressions that are not suitable for use in #if processing directives.






share|improve this answer



































    4














    The first two implementations are not conforming to the C standard, because they don't permit UINT8_C(42) in #if directives:



    #if UINT8_C(42) == 42 // <- should be a valid expression


    N1570 7.20.4/3:




    Each invocation of one of these macros shall expand to an integer constant expression suitable for use in #if preprocessing directives. The type of the expression shall have the same type as would an expression of the corresponding type converted according to the integer promotions. The value of the expression shall be that of the argument.







    share|improve this answer























    • 1





      In addition, the second one doesn't conform to the C standard because it expands to C++ code.

      – Shawn
      5 hours ago



















    2














    The GNU C library is not correct. Per C11 7.20.4.1 Macros for minimum-width integer constants UINTN_C(value) is defined as




    The macro UINTN_C(value) shall expand to an integer constant expression corresponding to the type uint_leastN_t.




    So it is not proper the they just use c since c may or may not be a uint_least8_t.






    share|improve this answer





















    • 3





      At least for the C language (I've no idea about C++), if the uint_least8_t value would be promoted to an int anyway, then #define UINT8_C(c) c is fair enough. The unsuffixed integer constant c is required to be within the range of uint_least8_t (C11 7.20.4p2), so using an out-of-range argument is UB.

      – Ian Abbott
      7 hours ago








    • 1





      But -1 is not representable by uint_least8_t so it is UB,.

      – Ian Abbott
      7 hours ago








    • 1





      @IanAbbott That is not correct. Any value is representable in a uint8_least_t as it uses modulo 2^8 arithmetic. doing (uint8_least_t)-1 give you the max value.

      – NathanOliver
      7 hours ago








    • 2





      C11 7.20.4p2: "The argument in any instance of these macros shall be an unsuffixed integer constant (as defined in 6.4.4.1) with a value that does not exceed the limits for the corresponding type." (emphasis mine)

      – Ian Abbott
      7 hours ago






    • 1





      Then it is still UB because -1 is not an integer constant as required by 7.20.4p2.

      – Ian Abbott
      7 hours ago
















    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f57417154%2fwhy-do-implementations-of-stdint-h-disagree-on-the-definition-of-uint8-c%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    3 Answers
    3






    active

    oldest

    votes








    3 Answers
    3






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    5














    If an int can represent all the values of a uint_least8_t then the GNU implementation of the UINT8_C(value) macro as #define UINT8_C(c) c conforms to the C standard.



    As per C11 7.20.4 Macros for integer constants paragraph 2:




    The argument in any instance of these macros shall be an unsuffixed integer constant (as defined in 6.4.4.1) with a value that does not exceed the limits for the corresponding type.




    For example, if UINT_LEAST8_MAX is 255, the following usage examples are legal:




    • UINT8_C(0)

    • UINT8_C(255)

    • UINT8_C(0377)

    • UINT8_C(0xff)


    But the following usage examples result in undefined behavior:





    • UINT8_C(-1) — not an integer constant as defined in 6.4.4.1


    • UINT8_C(1u) — not an unsuffixed integer constant


    • UINT8_C(256) — exceeds the limits of uint_least8_t for this implementation


    The signed equivalent INT8_C(-1) is also undefined behavior for the same reasons.



    If UINT_LEAST8_MAX is 255, a legal instance of UINT8_C(value) will expand to an integer constant expression and its type will be int due to integer promotions, as per paragraph 3:




    Each invocation of one of these macros shall expand to an integer constant expression suitable for use in #if preprocessing directives. The type of the expression shall have the same type as would an expression of the corresponding type converted according to the integer promotions. The value of the expression shall be that of the argument.




    Thus for any legal invocation of UINT8_C(value), the expansion of this to value by any implementation where an int can represent all the values of uint_least8_t is perfectly standard conforming. For any illegal invocation of UINT8_C(value) you may not get the result you were expecting due to undefined behavior.



    [EDIT added for completeness] As pointed out in cpplearner's answer, the other implementations of UINT8_C(value) shown in OP's question are invalid because they expand to expressions that are not suitable for use in #if processing directives.






    share|improve this answer
































      5














      If an int can represent all the values of a uint_least8_t then the GNU implementation of the UINT8_C(value) macro as #define UINT8_C(c) c conforms to the C standard.



      As per C11 7.20.4 Macros for integer constants paragraph 2:




      The argument in any instance of these macros shall be an unsuffixed integer constant (as defined in 6.4.4.1) with a value that does not exceed the limits for the corresponding type.




      For example, if UINT_LEAST8_MAX is 255, the following usage examples are legal:




      • UINT8_C(0)

      • UINT8_C(255)

      • UINT8_C(0377)

      • UINT8_C(0xff)


      But the following usage examples result in undefined behavior:





      • UINT8_C(-1) — not an integer constant as defined in 6.4.4.1


      • UINT8_C(1u) — not an unsuffixed integer constant


      • UINT8_C(256) — exceeds the limits of uint_least8_t for this implementation


      The signed equivalent INT8_C(-1) is also undefined behavior for the same reasons.



      If UINT_LEAST8_MAX is 255, a legal instance of UINT8_C(value) will expand to an integer constant expression and its type will be int due to integer promotions, as per paragraph 3:




      Each invocation of one of these macros shall expand to an integer constant expression suitable for use in #if preprocessing directives. The type of the expression shall have the same type as would an expression of the corresponding type converted according to the integer promotions. The value of the expression shall be that of the argument.




      Thus for any legal invocation of UINT8_C(value), the expansion of this to value by any implementation where an int can represent all the values of uint_least8_t is perfectly standard conforming. For any illegal invocation of UINT8_C(value) you may not get the result you were expecting due to undefined behavior.



      [EDIT added for completeness] As pointed out in cpplearner's answer, the other implementations of UINT8_C(value) shown in OP's question are invalid because they expand to expressions that are not suitable for use in #if processing directives.






      share|improve this answer






























        5












        5








        5







        If an int can represent all the values of a uint_least8_t then the GNU implementation of the UINT8_C(value) macro as #define UINT8_C(c) c conforms to the C standard.



        As per C11 7.20.4 Macros for integer constants paragraph 2:




        The argument in any instance of these macros shall be an unsuffixed integer constant (as defined in 6.4.4.1) with a value that does not exceed the limits for the corresponding type.




        For example, if UINT_LEAST8_MAX is 255, the following usage examples are legal:




        • UINT8_C(0)

        • UINT8_C(255)

        • UINT8_C(0377)

        • UINT8_C(0xff)


        But the following usage examples result in undefined behavior:





        • UINT8_C(-1) — not an integer constant as defined in 6.4.4.1


        • UINT8_C(1u) — not an unsuffixed integer constant


        • UINT8_C(256) — exceeds the limits of uint_least8_t for this implementation


        The signed equivalent INT8_C(-1) is also undefined behavior for the same reasons.



        If UINT_LEAST8_MAX is 255, a legal instance of UINT8_C(value) will expand to an integer constant expression and its type will be int due to integer promotions, as per paragraph 3:




        Each invocation of one of these macros shall expand to an integer constant expression suitable for use in #if preprocessing directives. The type of the expression shall have the same type as would an expression of the corresponding type converted according to the integer promotions. The value of the expression shall be that of the argument.




        Thus for any legal invocation of UINT8_C(value), the expansion of this to value by any implementation where an int can represent all the values of uint_least8_t is perfectly standard conforming. For any illegal invocation of UINT8_C(value) you may not get the result you were expecting due to undefined behavior.



        [EDIT added for completeness] As pointed out in cpplearner's answer, the other implementations of UINT8_C(value) shown in OP's question are invalid because they expand to expressions that are not suitable for use in #if processing directives.






        share|improve this answer















        If an int can represent all the values of a uint_least8_t then the GNU implementation of the UINT8_C(value) macro as #define UINT8_C(c) c conforms to the C standard.



        As per C11 7.20.4 Macros for integer constants paragraph 2:




        The argument in any instance of these macros shall be an unsuffixed integer constant (as defined in 6.4.4.1) with a value that does not exceed the limits for the corresponding type.




        For example, if UINT_LEAST8_MAX is 255, the following usage examples are legal:




        • UINT8_C(0)

        • UINT8_C(255)

        • UINT8_C(0377)

        • UINT8_C(0xff)


        But the following usage examples result in undefined behavior:





        • UINT8_C(-1) — not an integer constant as defined in 6.4.4.1


        • UINT8_C(1u) — not an unsuffixed integer constant


        • UINT8_C(256) — exceeds the limits of uint_least8_t for this implementation


        The signed equivalent INT8_C(-1) is also undefined behavior for the same reasons.



        If UINT_LEAST8_MAX is 255, a legal instance of UINT8_C(value) will expand to an integer constant expression and its type will be int due to integer promotions, as per paragraph 3:




        Each invocation of one of these macros shall expand to an integer constant expression suitable for use in #if preprocessing directives. The type of the expression shall have the same type as would an expression of the corresponding type converted according to the integer promotions. The value of the expression shall be that of the argument.




        Thus for any legal invocation of UINT8_C(value), the expansion of this to value by any implementation where an int can represent all the values of uint_least8_t is perfectly standard conforming. For any illegal invocation of UINT8_C(value) you may not get the result you were expecting due to undefined behavior.



        [EDIT added for completeness] As pointed out in cpplearner's answer, the other implementations of UINT8_C(value) shown in OP's question are invalid because they expand to expressions that are not suitable for use in #if processing directives.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited 5 hours ago

























        answered 6 hours ago









        Ian AbbottIan Abbott

        4,1437 silver badges17 bronze badges




        4,1437 silver badges17 bronze badges




























            4














            The first two implementations are not conforming to the C standard, because they don't permit UINT8_C(42) in #if directives:



            #if UINT8_C(42) == 42 // <- should be a valid expression


            N1570 7.20.4/3:




            Each invocation of one of these macros shall expand to an integer constant expression suitable for use in #if preprocessing directives. The type of the expression shall have the same type as would an expression of the corresponding type converted according to the integer promotions. The value of the expression shall be that of the argument.







            share|improve this answer























            • 1





              In addition, the second one doesn't conform to the C standard because it expands to C++ code.

              – Shawn
              5 hours ago
















            4














            The first two implementations are not conforming to the C standard, because they don't permit UINT8_C(42) in #if directives:



            #if UINT8_C(42) == 42 // <- should be a valid expression


            N1570 7.20.4/3:




            Each invocation of one of these macros shall expand to an integer constant expression suitable for use in #if preprocessing directives. The type of the expression shall have the same type as would an expression of the corresponding type converted according to the integer promotions. The value of the expression shall be that of the argument.







            share|improve this answer























            • 1





              In addition, the second one doesn't conform to the C standard because it expands to C++ code.

              – Shawn
              5 hours ago














            4












            4








            4







            The first two implementations are not conforming to the C standard, because they don't permit UINT8_C(42) in #if directives:



            #if UINT8_C(42) == 42 // <- should be a valid expression


            N1570 7.20.4/3:




            Each invocation of one of these macros shall expand to an integer constant expression suitable for use in #if preprocessing directives. The type of the expression shall have the same type as would an expression of the corresponding type converted according to the integer promotions. The value of the expression shall be that of the argument.







            share|improve this answer















            The first two implementations are not conforming to the C standard, because they don't permit UINT8_C(42) in #if directives:



            #if UINT8_C(42) == 42 // <- should be a valid expression


            N1570 7.20.4/3:




            Each invocation of one of these macros shall expand to an integer constant expression suitable for use in #if preprocessing directives. The type of the expression shall have the same type as would an expression of the corresponding type converted according to the integer promotions. The value of the expression shall be that of the argument.








            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited 5 hours ago

























            answered 6 hours ago









            cpplearnercpplearner

            6,6342 gold badges26 silver badges47 bronze badges




            6,6342 gold badges26 silver badges47 bronze badges











            • 1





              In addition, the second one doesn't conform to the C standard because it expands to C++ code.

              – Shawn
              5 hours ago














            • 1





              In addition, the second one doesn't conform to the C standard because it expands to C++ code.

              – Shawn
              5 hours ago








            1




            1





            In addition, the second one doesn't conform to the C standard because it expands to C++ code.

            – Shawn
            5 hours ago





            In addition, the second one doesn't conform to the C standard because it expands to C++ code.

            – Shawn
            5 hours ago











            2














            The GNU C library is not correct. Per C11 7.20.4.1 Macros for minimum-width integer constants UINTN_C(value) is defined as




            The macro UINTN_C(value) shall expand to an integer constant expression corresponding to the type uint_leastN_t.




            So it is not proper the they just use c since c may or may not be a uint_least8_t.






            share|improve this answer





















            • 3





              At least for the C language (I've no idea about C++), if the uint_least8_t value would be promoted to an int anyway, then #define UINT8_C(c) c is fair enough. The unsuffixed integer constant c is required to be within the range of uint_least8_t (C11 7.20.4p2), so using an out-of-range argument is UB.

              – Ian Abbott
              7 hours ago








            • 1





              But -1 is not representable by uint_least8_t so it is UB,.

              – Ian Abbott
              7 hours ago








            • 1





              @IanAbbott That is not correct. Any value is representable in a uint8_least_t as it uses modulo 2^8 arithmetic. doing (uint8_least_t)-1 give you the max value.

              – NathanOliver
              7 hours ago








            • 2





              C11 7.20.4p2: "The argument in any instance of these macros shall be an unsuffixed integer constant (as defined in 6.4.4.1) with a value that does not exceed the limits for the corresponding type." (emphasis mine)

              – Ian Abbott
              7 hours ago






            • 1





              Then it is still UB because -1 is not an integer constant as required by 7.20.4p2.

              – Ian Abbott
              7 hours ago


















            2














            The GNU C library is not correct. Per C11 7.20.4.1 Macros for minimum-width integer constants UINTN_C(value) is defined as




            The macro UINTN_C(value) shall expand to an integer constant expression corresponding to the type uint_leastN_t.




            So it is not proper the they just use c since c may or may not be a uint_least8_t.






            share|improve this answer





















            • 3





              At least for the C language (I've no idea about C++), if the uint_least8_t value would be promoted to an int anyway, then #define UINT8_C(c) c is fair enough. The unsuffixed integer constant c is required to be within the range of uint_least8_t (C11 7.20.4p2), so using an out-of-range argument is UB.

              – Ian Abbott
              7 hours ago








            • 1





              But -1 is not representable by uint_least8_t so it is UB,.

              – Ian Abbott
              7 hours ago








            • 1





              @IanAbbott That is not correct. Any value is representable in a uint8_least_t as it uses modulo 2^8 arithmetic. doing (uint8_least_t)-1 give you the max value.

              – NathanOliver
              7 hours ago








            • 2





              C11 7.20.4p2: "The argument in any instance of these macros shall be an unsuffixed integer constant (as defined in 6.4.4.1) with a value that does not exceed the limits for the corresponding type." (emphasis mine)

              – Ian Abbott
              7 hours ago






            • 1





              Then it is still UB because -1 is not an integer constant as required by 7.20.4p2.

              – Ian Abbott
              7 hours ago
















            2












            2








            2







            The GNU C library is not correct. Per C11 7.20.4.1 Macros for minimum-width integer constants UINTN_C(value) is defined as




            The macro UINTN_C(value) shall expand to an integer constant expression corresponding to the type uint_leastN_t.




            So it is not proper the they just use c since c may or may not be a uint_least8_t.






            share|improve this answer













            The GNU C library is not correct. Per C11 7.20.4.1 Macros for minimum-width integer constants UINTN_C(value) is defined as




            The macro UINTN_C(value) shall expand to an integer constant expression corresponding to the type uint_leastN_t.




            So it is not proper the they just use c since c may or may not be a uint_least8_t.







            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered 8 hours ago









            NathanOliverNathanOliver

            111k19 gold badges175 silver badges252 bronze badges




            111k19 gold badges175 silver badges252 bronze badges











            • 3





              At least for the C language (I've no idea about C++), if the uint_least8_t value would be promoted to an int anyway, then #define UINT8_C(c) c is fair enough. The unsuffixed integer constant c is required to be within the range of uint_least8_t (C11 7.20.4p2), so using an out-of-range argument is UB.

              – Ian Abbott
              7 hours ago








            • 1





              But -1 is not representable by uint_least8_t so it is UB,.

              – Ian Abbott
              7 hours ago








            • 1





              @IanAbbott That is not correct. Any value is representable in a uint8_least_t as it uses modulo 2^8 arithmetic. doing (uint8_least_t)-1 give you the max value.

              – NathanOliver
              7 hours ago








            • 2





              C11 7.20.4p2: "The argument in any instance of these macros shall be an unsuffixed integer constant (as defined in 6.4.4.1) with a value that does not exceed the limits for the corresponding type." (emphasis mine)

              – Ian Abbott
              7 hours ago






            • 1





              Then it is still UB because -1 is not an integer constant as required by 7.20.4p2.

              – Ian Abbott
              7 hours ago
















            • 3





              At least for the C language (I've no idea about C++), if the uint_least8_t value would be promoted to an int anyway, then #define UINT8_C(c) c is fair enough. The unsuffixed integer constant c is required to be within the range of uint_least8_t (C11 7.20.4p2), so using an out-of-range argument is UB.

              – Ian Abbott
              7 hours ago








            • 1





              But -1 is not representable by uint_least8_t so it is UB,.

              – Ian Abbott
              7 hours ago








            • 1





              @IanAbbott That is not correct. Any value is representable in a uint8_least_t as it uses modulo 2^8 arithmetic. doing (uint8_least_t)-1 give you the max value.

              – NathanOliver
              7 hours ago








            • 2





              C11 7.20.4p2: "The argument in any instance of these macros shall be an unsuffixed integer constant (as defined in 6.4.4.1) with a value that does not exceed the limits for the corresponding type." (emphasis mine)

              – Ian Abbott
              7 hours ago






            • 1





              Then it is still UB because -1 is not an integer constant as required by 7.20.4p2.

              – Ian Abbott
              7 hours ago










            3




            3





            At least for the C language (I've no idea about C++), if the uint_least8_t value would be promoted to an int anyway, then #define UINT8_C(c) c is fair enough. The unsuffixed integer constant c is required to be within the range of uint_least8_t (C11 7.20.4p2), so using an out-of-range argument is UB.

            – Ian Abbott
            7 hours ago







            At least for the C language (I've no idea about C++), if the uint_least8_t value would be promoted to an int anyway, then #define UINT8_C(c) c is fair enough. The unsuffixed integer constant c is required to be within the range of uint_least8_t (C11 7.20.4p2), so using an out-of-range argument is UB.

            – Ian Abbott
            7 hours ago






            1




            1





            But -1 is not representable by uint_least8_t so it is UB,.

            – Ian Abbott
            7 hours ago







            But -1 is not representable by uint_least8_t so it is UB,.

            – Ian Abbott
            7 hours ago






            1




            1





            @IanAbbott That is not correct. Any value is representable in a uint8_least_t as it uses modulo 2^8 arithmetic. doing (uint8_least_t)-1 give you the max value.

            – NathanOliver
            7 hours ago







            @IanAbbott That is not correct. Any value is representable in a uint8_least_t as it uses modulo 2^8 arithmetic. doing (uint8_least_t)-1 give you the max value.

            – NathanOliver
            7 hours ago






            2




            2





            C11 7.20.4p2: "The argument in any instance of these macros shall be an unsuffixed integer constant (as defined in 6.4.4.1) with a value that does not exceed the limits for the corresponding type." (emphasis mine)

            – Ian Abbott
            7 hours ago





            C11 7.20.4p2: "The argument in any instance of these macros shall be an unsuffixed integer constant (as defined in 6.4.4.1) with a value that does not exceed the limits for the corresponding type." (emphasis mine)

            – Ian Abbott
            7 hours ago




            1




            1





            Then it is still UB because -1 is not an integer constant as required by 7.20.4p2.

            – Ian Abbott
            7 hours ago







            Then it is still UB because -1 is not an integer constant as required by 7.20.4p2.

            – Ian Abbott
            7 hours ago




















            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f57417154%2fwhy-do-implementations-of-stdint-h-disagree-on-the-definition-of-uint8-c%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Hudson River Historic District Contents Geography History The district today Aesthetics Cultural...

            The number designs the writing. Feandra Aversely Definition: The act of ingrafting a sprig or shoot of one...

            Ayherre Geografie Demografie Externe links Navigatiemenu43° 23′ NB, 1° 15′ WL43° 23′ NB, 1°...