What is the point of the {U,}INTn_C macros in stdint.h?
up vote
3
down vote
favorite
When are these macros actually needed?
My systems (gcc/glibc/linux/x86_64) stdint.h
uses (__
-prefixed) variant of these to define:
# define INT64_MIN (-__INT64_C(9223372036854775807)-1)
# define INT64_MAX (__INT64_C(9223372036854775807))
# define UINT64_MAX (__UINT64_C(18446744073709551615))
# define INT_LEAST64_MIN (-__INT64_C(9223372036854775807)-1)
# define INT_LEAST64_MAX (__INT64_C(9223372036854775807))
# define UINT_LEAST64_MAX (__UINT64_C(18446744073709551615))
# define INT_FAST64_MIN (-__INT64_C(9223372036854775807)-1)
# define INT_FAST64_MAX (__INT64_C(9223372036854775807))
# define UINT_FAST64_MAX (__UINT64_C(18446744073709551615))
# define INTMAX_MIN (-__INT64_C(9223372036854775807)-1)
# define INTMAX_MAX (__INT64_C(9223372036854775807))
# define UINTMAX_MAX (__UINT64_C(18446744073709551615))
Yet for limits.h
it seems to make do with:
# define LONG_MAX 9223372036854775807L
# define ULONG_MAX 18446744073709551615UL
Why can't stdint.h
forget about the _C
macros and simply do:
# define INT_LEAST64_MAX 9223372036854775807 //let it grow as needed
# define UINT_LEAST64_MAX 18446744073709551615U //just the U
What are the use cases for these macros?
The only one I could think of is where I want a sufficiently wide constant usable in cpp conditionals and at the same time I don't want it too wide:
//C guarantees longs are at least 32 bits wide
#define THREE_GIGS_BUT_MAYBE_TOO_WIDE (1L<<30)
#define THREE_GIGS (INT32_C(1)<<30) //possibly narrower than the define above
c language-lawyer
add a comment |
up vote
3
down vote
favorite
When are these macros actually needed?
My systems (gcc/glibc/linux/x86_64) stdint.h
uses (__
-prefixed) variant of these to define:
# define INT64_MIN (-__INT64_C(9223372036854775807)-1)
# define INT64_MAX (__INT64_C(9223372036854775807))
# define UINT64_MAX (__UINT64_C(18446744073709551615))
# define INT_LEAST64_MIN (-__INT64_C(9223372036854775807)-1)
# define INT_LEAST64_MAX (__INT64_C(9223372036854775807))
# define UINT_LEAST64_MAX (__UINT64_C(18446744073709551615))
# define INT_FAST64_MIN (-__INT64_C(9223372036854775807)-1)
# define INT_FAST64_MAX (__INT64_C(9223372036854775807))
# define UINT_FAST64_MAX (__UINT64_C(18446744073709551615))
# define INTMAX_MIN (-__INT64_C(9223372036854775807)-1)
# define INTMAX_MAX (__INT64_C(9223372036854775807))
# define UINTMAX_MAX (__UINT64_C(18446744073709551615))
Yet for limits.h
it seems to make do with:
# define LONG_MAX 9223372036854775807L
# define ULONG_MAX 18446744073709551615UL
Why can't stdint.h
forget about the _C
macros and simply do:
# define INT_LEAST64_MAX 9223372036854775807 //let it grow as needed
# define UINT_LEAST64_MAX 18446744073709551615U //just the U
What are the use cases for these macros?
The only one I could think of is where I want a sufficiently wide constant usable in cpp conditionals and at the same time I don't want it too wide:
//C guarantees longs are at least 32 bits wide
#define THREE_GIGS_BUT_MAYBE_TOO_WIDE (1L<<30)
#define THREE_GIGS (INT32_C(1)<<30) //possibly narrower than the define above
c language-lawyer
Most likely because LL is “at least 64bit” but not necessarily exactly 64bit. And different platforms may have different definitions so a macro makes it simple to change things without changing the common headers.
– Sami Kuhmonen
Nov 10 at 20:23
System headers are not necessarily designed exclusively for standards conforming C compilers.
– n.m.
Nov 10 at 21:11
Possible duplicate of When should I use UINT32_C(), INT32_C(),... macros in C?
– Giovanni Cerretani
Nov 10 at 22:06
add a comment |
up vote
3
down vote
favorite
up vote
3
down vote
favorite
When are these macros actually needed?
My systems (gcc/glibc/linux/x86_64) stdint.h
uses (__
-prefixed) variant of these to define:
# define INT64_MIN (-__INT64_C(9223372036854775807)-1)
# define INT64_MAX (__INT64_C(9223372036854775807))
# define UINT64_MAX (__UINT64_C(18446744073709551615))
# define INT_LEAST64_MIN (-__INT64_C(9223372036854775807)-1)
# define INT_LEAST64_MAX (__INT64_C(9223372036854775807))
# define UINT_LEAST64_MAX (__UINT64_C(18446744073709551615))
# define INT_FAST64_MIN (-__INT64_C(9223372036854775807)-1)
# define INT_FAST64_MAX (__INT64_C(9223372036854775807))
# define UINT_FAST64_MAX (__UINT64_C(18446744073709551615))
# define INTMAX_MIN (-__INT64_C(9223372036854775807)-1)
# define INTMAX_MAX (__INT64_C(9223372036854775807))
# define UINTMAX_MAX (__UINT64_C(18446744073709551615))
Yet for limits.h
it seems to make do with:
# define LONG_MAX 9223372036854775807L
# define ULONG_MAX 18446744073709551615UL
Why can't stdint.h
forget about the _C
macros and simply do:
# define INT_LEAST64_MAX 9223372036854775807 //let it grow as needed
# define UINT_LEAST64_MAX 18446744073709551615U //just the U
What are the use cases for these macros?
The only one I could think of is where I want a sufficiently wide constant usable in cpp conditionals and at the same time I don't want it too wide:
//C guarantees longs are at least 32 bits wide
#define THREE_GIGS_BUT_MAYBE_TOO_WIDE (1L<<30)
#define THREE_GIGS (INT32_C(1)<<30) //possibly narrower than the define above
c language-lawyer
When are these macros actually needed?
My systems (gcc/glibc/linux/x86_64) stdint.h
uses (__
-prefixed) variant of these to define:
# define INT64_MIN (-__INT64_C(9223372036854775807)-1)
# define INT64_MAX (__INT64_C(9223372036854775807))
# define UINT64_MAX (__UINT64_C(18446744073709551615))
# define INT_LEAST64_MIN (-__INT64_C(9223372036854775807)-1)
# define INT_LEAST64_MAX (__INT64_C(9223372036854775807))
# define UINT_LEAST64_MAX (__UINT64_C(18446744073709551615))
# define INT_FAST64_MIN (-__INT64_C(9223372036854775807)-1)
# define INT_FAST64_MAX (__INT64_C(9223372036854775807))
# define UINT_FAST64_MAX (__UINT64_C(18446744073709551615))
# define INTMAX_MIN (-__INT64_C(9223372036854775807)-1)
# define INTMAX_MAX (__INT64_C(9223372036854775807))
# define UINTMAX_MAX (__UINT64_C(18446744073709551615))
Yet for limits.h
it seems to make do with:
# define LONG_MAX 9223372036854775807L
# define ULONG_MAX 18446744073709551615UL
Why can't stdint.h
forget about the _C
macros and simply do:
# define INT_LEAST64_MAX 9223372036854775807 //let it grow as needed
# define UINT_LEAST64_MAX 18446744073709551615U //just the U
What are the use cases for these macros?
The only one I could think of is where I want a sufficiently wide constant usable in cpp conditionals and at the same time I don't want it too wide:
//C guarantees longs are at least 32 bits wide
#define THREE_GIGS_BUT_MAYBE_TOO_WIDE (1L<<30)
#define THREE_GIGS (INT32_C(1)<<30) //possibly narrower than the define above
c language-lawyer
c language-lawyer
edited Nov 10 at 20:53
Jonathan Leffler
554k886581012
554k886581012
asked Nov 10 at 20:13
PSkocik
31k54568
31k54568
Most likely because LL is “at least 64bit” but not necessarily exactly 64bit. And different platforms may have different definitions so a macro makes it simple to change things without changing the common headers.
– Sami Kuhmonen
Nov 10 at 20:23
System headers are not necessarily designed exclusively for standards conforming C compilers.
– n.m.
Nov 10 at 21:11
Possible duplicate of When should I use UINT32_C(), INT32_C(),... macros in C?
– Giovanni Cerretani
Nov 10 at 22:06
add a comment |
Most likely because LL is “at least 64bit” but not necessarily exactly 64bit. And different platforms may have different definitions so a macro makes it simple to change things without changing the common headers.
– Sami Kuhmonen
Nov 10 at 20:23
System headers are not necessarily designed exclusively for standards conforming C compilers.
– n.m.
Nov 10 at 21:11
Possible duplicate of When should I use UINT32_C(), INT32_C(),... macros in C?
– Giovanni Cerretani
Nov 10 at 22:06
Most likely because LL is “at least 64bit” but not necessarily exactly 64bit. And different platforms may have different definitions so a macro makes it simple to change things without changing the common headers.
– Sami Kuhmonen
Nov 10 at 20:23
Most likely because LL is “at least 64bit” but not necessarily exactly 64bit. And different platforms may have different definitions so a macro makes it simple to change things without changing the common headers.
– Sami Kuhmonen
Nov 10 at 20:23
System headers are not necessarily designed exclusively for standards conforming C compilers.
– n.m.
Nov 10 at 21:11
System headers are not necessarily designed exclusively for standards conforming C compilers.
– n.m.
Nov 10 at 21:11
Possible duplicate of When should I use UINT32_C(), INT32_C(),... macros in C?
– Giovanni Cerretani
Nov 10 at 22:06
Possible duplicate of When should I use UINT32_C(), INT32_C(),... macros in C?
– Giovanni Cerretani
Nov 10 at 22:06
add a comment |
2 Answers
2
active
oldest
votes
up vote
2
down vote
The point of e.g. __UINT64_C(x)
seems to be to attach the correct kind of suffix to x
.
In this way, the implementer of the C standard library header files are able to separate the numerical constants (which are the same on all platforms) from the suffixes (which depend on the integer size).
For example, when building a 64-bit executable, the __UINT64_C(x)
would evaluate to x ## UL
, while when building a 32-bit executable, it would evaluate to x ## ULL
.
Edit: as @PSkocik points out, for signed integers this macro is not necessary. My guess is that it is still present as (1) the suffix is necessary for unsigned values and (2) the authors wanted to keep the code consistent for signed and unsigned constants.
9223372036854775807
doesn't need any suffix to be typedlong
on anLP64
platform. And if it doesn't fitlong
it'll be automaticallylong long
(as per port70.net/~nsz/c/c11/n1570.html#6.4.4.1p5). And it must fit at leastlong long
becauselong long
is required to be present at least 64 bits wide.
– PSkocik
Nov 10 at 20:41
add a comment |
up vote
1
down vote
What is the point of the
{U,}INTn_C
macros in<stdint.h>
?
They insure a minimal type width and sign-ness for a constant.
They "expand to an integer constant expression corresponding to the type (u)int_leastN_t.
"
123 << 50 // likely int overflow (UB)
INT32_C(123) << 50 // likely int overflow (UB)
INT64_C(123) << 50 // well defined.
INT32_C(123)*2000000000 // likely int overflow (UB)
UINT32_C(123)*2000000000 // well defined - even though it may mathematically overflow
Useful when defining computed constants.
// well defined, but the wrong product when unsigned is 32-bit
#define TBYTE (1024u*1024*1024*1024)
// well defined, and specified to be 1099511627776u
#define TBYTE (UINT64_C(1024)*1024*1024*1024)
It also affects code via _Generic
. The below could steer code to unsigned long
, unsigned
and unsigned long long
.
(unsigned long) 123
UINT32_C(123)
UINT64_C(123)
add a comment |
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
2
down vote
The point of e.g. __UINT64_C(x)
seems to be to attach the correct kind of suffix to x
.
In this way, the implementer of the C standard library header files are able to separate the numerical constants (which are the same on all platforms) from the suffixes (which depend on the integer size).
For example, when building a 64-bit executable, the __UINT64_C(x)
would evaluate to x ## UL
, while when building a 32-bit executable, it would evaluate to x ## ULL
.
Edit: as @PSkocik points out, for signed integers this macro is not necessary. My guess is that it is still present as (1) the suffix is necessary for unsigned values and (2) the authors wanted to keep the code consistent for signed and unsigned constants.
9223372036854775807
doesn't need any suffix to be typedlong
on anLP64
platform. And if it doesn't fitlong
it'll be automaticallylong long
(as per port70.net/~nsz/c/c11/n1570.html#6.4.4.1p5). And it must fit at leastlong long
becauselong long
is required to be present at least 64 bits wide.
– PSkocik
Nov 10 at 20:41
add a comment |
up vote
2
down vote
The point of e.g. __UINT64_C(x)
seems to be to attach the correct kind of suffix to x
.
In this way, the implementer of the C standard library header files are able to separate the numerical constants (which are the same on all platforms) from the suffixes (which depend on the integer size).
For example, when building a 64-bit executable, the __UINT64_C(x)
would evaluate to x ## UL
, while when building a 32-bit executable, it would evaluate to x ## ULL
.
Edit: as @PSkocik points out, for signed integers this macro is not necessary. My guess is that it is still present as (1) the suffix is necessary for unsigned values and (2) the authors wanted to keep the code consistent for signed and unsigned constants.
9223372036854775807
doesn't need any suffix to be typedlong
on anLP64
platform. And if it doesn't fitlong
it'll be automaticallylong long
(as per port70.net/~nsz/c/c11/n1570.html#6.4.4.1p5). And it must fit at leastlong long
becauselong long
is required to be present at least 64 bits wide.
– PSkocik
Nov 10 at 20:41
add a comment |
up vote
2
down vote
up vote
2
down vote
The point of e.g. __UINT64_C(x)
seems to be to attach the correct kind of suffix to x
.
In this way, the implementer of the C standard library header files are able to separate the numerical constants (which are the same on all platforms) from the suffixes (which depend on the integer size).
For example, when building a 64-bit executable, the __UINT64_C(x)
would evaluate to x ## UL
, while when building a 32-bit executable, it would evaluate to x ## ULL
.
Edit: as @PSkocik points out, for signed integers this macro is not necessary. My guess is that it is still present as (1) the suffix is necessary for unsigned values and (2) the authors wanted to keep the code consistent for signed and unsigned constants.
The point of e.g. __UINT64_C(x)
seems to be to attach the correct kind of suffix to x
.
In this way, the implementer of the C standard library header files are able to separate the numerical constants (which are the same on all platforms) from the suffixes (which depend on the integer size).
For example, when building a 64-bit executable, the __UINT64_C(x)
would evaluate to x ## UL
, while when building a 32-bit executable, it would evaluate to x ## ULL
.
Edit: as @PSkocik points out, for signed integers this macro is not necessary. My guess is that it is still present as (1) the suffix is necessary for unsigned values and (2) the authors wanted to keep the code consistent for signed and unsigned constants.
edited Nov 10 at 20:47
answered Nov 10 at 20:30
kfx
4,82821535
4,82821535
9223372036854775807
doesn't need any suffix to be typedlong
on anLP64
platform. And if it doesn't fitlong
it'll be automaticallylong long
(as per port70.net/~nsz/c/c11/n1570.html#6.4.4.1p5). And it must fit at leastlong long
becauselong long
is required to be present at least 64 bits wide.
– PSkocik
Nov 10 at 20:41
add a comment |
9223372036854775807
doesn't need any suffix to be typedlong
on anLP64
platform. And if it doesn't fitlong
it'll be automaticallylong long
(as per port70.net/~nsz/c/c11/n1570.html#6.4.4.1p5). And it must fit at leastlong long
becauselong long
is required to be present at least 64 bits wide.
– PSkocik
Nov 10 at 20:41
9223372036854775807
doesn't need any suffix to be typed long
on an LP64
platform. And if it doesn't fit long
it'll be automatically long long
(as per port70.net/~nsz/c/c11/n1570.html#6.4.4.1p5). And it must fit at least long long
because long long
is required to be present at least 64 bits wide.– PSkocik
Nov 10 at 20:41
9223372036854775807
doesn't need any suffix to be typed long
on an LP64
platform. And if it doesn't fit long
it'll be automatically long long
(as per port70.net/~nsz/c/c11/n1570.html#6.4.4.1p5). And it must fit at least long long
because long long
is required to be present at least 64 bits wide.– PSkocik
Nov 10 at 20:41
add a comment |
up vote
1
down vote
What is the point of the
{U,}INTn_C
macros in<stdint.h>
?
They insure a minimal type width and sign-ness for a constant.
They "expand to an integer constant expression corresponding to the type (u)int_leastN_t.
"
123 << 50 // likely int overflow (UB)
INT32_C(123) << 50 // likely int overflow (UB)
INT64_C(123) << 50 // well defined.
INT32_C(123)*2000000000 // likely int overflow (UB)
UINT32_C(123)*2000000000 // well defined - even though it may mathematically overflow
Useful when defining computed constants.
// well defined, but the wrong product when unsigned is 32-bit
#define TBYTE (1024u*1024*1024*1024)
// well defined, and specified to be 1099511627776u
#define TBYTE (UINT64_C(1024)*1024*1024*1024)
It also affects code via _Generic
. The below could steer code to unsigned long
, unsigned
and unsigned long long
.
(unsigned long) 123
UINT32_C(123)
UINT64_C(123)
add a comment |
up vote
1
down vote
What is the point of the
{U,}INTn_C
macros in<stdint.h>
?
They insure a minimal type width and sign-ness for a constant.
They "expand to an integer constant expression corresponding to the type (u)int_leastN_t.
"
123 << 50 // likely int overflow (UB)
INT32_C(123) << 50 // likely int overflow (UB)
INT64_C(123) << 50 // well defined.
INT32_C(123)*2000000000 // likely int overflow (UB)
UINT32_C(123)*2000000000 // well defined - even though it may mathematically overflow
Useful when defining computed constants.
// well defined, but the wrong product when unsigned is 32-bit
#define TBYTE (1024u*1024*1024*1024)
// well defined, and specified to be 1099511627776u
#define TBYTE (UINT64_C(1024)*1024*1024*1024)
It also affects code via _Generic
. The below could steer code to unsigned long
, unsigned
and unsigned long long
.
(unsigned long) 123
UINT32_C(123)
UINT64_C(123)
add a comment |
up vote
1
down vote
up vote
1
down vote
What is the point of the
{U,}INTn_C
macros in<stdint.h>
?
They insure a minimal type width and sign-ness for a constant.
They "expand to an integer constant expression corresponding to the type (u)int_leastN_t.
"
123 << 50 // likely int overflow (UB)
INT32_C(123) << 50 // likely int overflow (UB)
INT64_C(123) << 50 // well defined.
INT32_C(123)*2000000000 // likely int overflow (UB)
UINT32_C(123)*2000000000 // well defined - even though it may mathematically overflow
Useful when defining computed constants.
// well defined, but the wrong product when unsigned is 32-bit
#define TBYTE (1024u*1024*1024*1024)
// well defined, and specified to be 1099511627776u
#define TBYTE (UINT64_C(1024)*1024*1024*1024)
It also affects code via _Generic
. The below could steer code to unsigned long
, unsigned
and unsigned long long
.
(unsigned long) 123
UINT32_C(123)
UINT64_C(123)
What is the point of the
{U,}INTn_C
macros in<stdint.h>
?
They insure a minimal type width and sign-ness for a constant.
They "expand to an integer constant expression corresponding to the type (u)int_leastN_t.
"
123 << 50 // likely int overflow (UB)
INT32_C(123) << 50 // likely int overflow (UB)
INT64_C(123) << 50 // well defined.
INT32_C(123)*2000000000 // likely int overflow (UB)
UINT32_C(123)*2000000000 // well defined - even though it may mathematically overflow
Useful when defining computed constants.
// well defined, but the wrong product when unsigned is 32-bit
#define TBYTE (1024u*1024*1024*1024)
// well defined, and specified to be 1099511627776u
#define TBYTE (UINT64_C(1024)*1024*1024*1024)
It also affects code via _Generic
. The below could steer code to unsigned long
, unsigned
and unsigned long long
.
(unsigned long) 123
UINT32_C(123)
UINT64_C(123)
edited Nov 10 at 22:20
answered Nov 10 at 21:15
chux
78.4k869143
78.4k869143
add a comment |
add a comment |
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53243019%2fwhat-is-the-point-of-the-u-intn-c-macros-in-stdint-h%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
Most likely because LL is “at least 64bit” but not necessarily exactly 64bit. And different platforms may have different definitions so a macro makes it simple to change things without changing the common headers.
– Sami Kuhmonen
Nov 10 at 20:23
System headers are not necessarily designed exclusively for standards conforming C compilers.
– n.m.
Nov 10 at 21:11
Possible duplicate of When should I use UINT32_C(), INT32_C(),... macros in C?
– Giovanni Cerretani
Nov 10 at 22:06