Unexpected types from UINT32_C, UINTN_C
up vote
7
down vote
favorite
7.20.4.1 Macros for minimum-width integer constants
... The macroUINTN_C(value)
shall expand to an integer constant expression corresponding to the typeuint_leastN_t
. For example, ifuint_least64_t
is a name for the typeunsigned long long int
, thenUINT64_C(0x123
) might expand to the integer constant0x123ULL
. C11dr §7.20.4.1 1
The type of UINTN_C()
and friends are not as expected. See "Expected" comments in code output.
A) Is my compiler implementation wrong and the constant type should be uint_leastN_t
?
or
B) Should the type of constant from UINTN_C(value)
be the minimum of uint_leastN_t
, int
, unsigned
and type needed to encode the value?
or
C) something else?
I had expected that the type of the constants to correspond to uint_leastN_t
, but it appears to not be so under 2 conditions:
**1 If the macro corresponding type is below int/unsigned
, the constant is int/unsigned
**2 If the value exceeds the range of the uint_leastN_t
, then the type becomes a wider type constant.
§6.4.4.1 "The type of an integer constant is the first of the corresponding list in which its value can be represented ... (long list follows).
#include <limits.h>
#include <stdio.h>
#define type_of(X) _Generic((X),
unsigned long long: "unsigned long long",
unsigned long: "unsigned long",
unsigned: "unsigned",
int: "int",
unsigned short: "unsigned short",
default: "?"
)
int main() {
uint_least16_t u16 = 0;
uint_least32_t u32 = 0;
uint_least64_t u64 = 0;
printf("%zu %sn", sizeof(u16), type_of(u16));
printf("%zu %sn", sizeof(u32), type_of(u32));
printf("%zu %sn", sizeof(u64), type_of(u64));
puts("");
printf("%zu %sn", sizeof((uint_least16_t) UINT16_C(0)), type_of((uint_least16_t) UINT16_C(0)));
printf("%zu %sn", sizeof UINT16_C(0), type_of(UINT16_C(0)));
printf("%zu %sn", sizeof UINT16_C(0x1234), type_of(UINT16_C(0x1234)));
printf("%zu %sn", sizeof UINT16_C(0x12345), type_of(UINT16_C(0x12345)));
printf("%zu %sn", sizeof UINT32_C(0x12345678), type_of(UINT32_C(0x12345678)));
printf("%zu %sn", sizeof UINT32_C(0x123456789), type_of(UINT32_C(0x123456789)));
return 0;
//round_frac_test(-2.05446162500000000e+06, 205);
round_frac_test(fp_rand(), 6);
round_frac_tests(10000);
puts("Done");
return 0;
}
Output
2 unsigned short
4 unsigned
8 unsigned long long
2 unsigned short
4 int // Expected 2 unsigned short, see **1
4 int // Expected 2 unsigned short, see **1
4 int // Expected 2 unsigned short, see **2
4 unsigned
8 unsigned long long // Expected 4 unsigned, see **2
I am using (GNU C11 (GCC) version 5.4.0)
In forming this post, I am leaning toward B, yet I am looking for your rational for confirmation -one way of the other. If B is so, a disappointing part is that UINTN_C()
could result in a signed type.
I suppose that is what the "minimum-width" part is about.
c language-lawyer
|
show 1 more comment
up vote
7
down vote
favorite
7.20.4.1 Macros for minimum-width integer constants
... The macroUINTN_C(value)
shall expand to an integer constant expression corresponding to the typeuint_leastN_t
. For example, ifuint_least64_t
is a name for the typeunsigned long long int
, thenUINT64_C(0x123
) might expand to the integer constant0x123ULL
. C11dr §7.20.4.1 1
The type of UINTN_C()
and friends are not as expected. See "Expected" comments in code output.
A) Is my compiler implementation wrong and the constant type should be uint_leastN_t
?
or
B) Should the type of constant from UINTN_C(value)
be the minimum of uint_leastN_t
, int
, unsigned
and type needed to encode the value?
or
C) something else?
I had expected that the type of the constants to correspond to uint_leastN_t
, but it appears to not be so under 2 conditions:
**1 If the macro corresponding type is below int/unsigned
, the constant is int/unsigned
**2 If the value exceeds the range of the uint_leastN_t
, then the type becomes a wider type constant.
§6.4.4.1 "The type of an integer constant is the first of the corresponding list in which its value can be represented ... (long list follows).
#include <limits.h>
#include <stdio.h>
#define type_of(X) _Generic((X),
unsigned long long: "unsigned long long",
unsigned long: "unsigned long",
unsigned: "unsigned",
int: "int",
unsigned short: "unsigned short",
default: "?"
)
int main() {
uint_least16_t u16 = 0;
uint_least32_t u32 = 0;
uint_least64_t u64 = 0;
printf("%zu %sn", sizeof(u16), type_of(u16));
printf("%zu %sn", sizeof(u32), type_of(u32));
printf("%zu %sn", sizeof(u64), type_of(u64));
puts("");
printf("%zu %sn", sizeof((uint_least16_t) UINT16_C(0)), type_of((uint_least16_t) UINT16_C(0)));
printf("%zu %sn", sizeof UINT16_C(0), type_of(UINT16_C(0)));
printf("%zu %sn", sizeof UINT16_C(0x1234), type_of(UINT16_C(0x1234)));
printf("%zu %sn", sizeof UINT16_C(0x12345), type_of(UINT16_C(0x12345)));
printf("%zu %sn", sizeof UINT32_C(0x12345678), type_of(UINT32_C(0x12345678)));
printf("%zu %sn", sizeof UINT32_C(0x123456789), type_of(UINT32_C(0x123456789)));
return 0;
//round_frac_test(-2.05446162500000000e+06, 205);
round_frac_test(fp_rand(), 6);
round_frac_tests(10000);
puts("Done");
return 0;
}
Output
2 unsigned short
4 unsigned
8 unsigned long long
2 unsigned short
4 int // Expected 2 unsigned short, see **1
4 int // Expected 2 unsigned short, see **1
4 int // Expected 2 unsigned short, see **2
4 unsigned
8 unsigned long long // Expected 4 unsigned, see **2
I am using (GNU C11 (GCC) version 5.4.0)
In forming this post, I am leaning toward B, yet I am looking for your rational for confirmation -one way of the other. If B is so, a disappointing part is that UINTN_C()
could result in a signed type.
I suppose that is what the "minimum-width" part is about.
c language-lawyer
1
I think you have a very valid point. The glibc macros instdint.h
should be e.g.#define UINT16_C(c) ((uint16_t)(c))
and so on, whereas right now they are just#define UINT16_C(c) c
(orc # U
,c # UL
,c # ULL
for larger types). Care to file a bug report? It usually only takes about a year for a tested patch to be accepted, and another year or so to dribble down to Linux distributions, in my experience.
– Nominal Animal
Aug 2 '17 at 17:14
1
Could this hinge on the corresponding in "shall expand to an integer constant expression corresponding to the typeuint_leastN_t
." In §6.2.5 6 there is "For each of the signed integer types, there is a corresponding (but different) unsigned integer type"; that is, maybe a type corresponding to an unsigned integer type need not be unsigned?
– David Bowling
Aug 2 '17 at 17:20
MSVC isn't much better:#define UINT16_C(x) (x)
– dbush
Aug 2 '17 at 17:22
@dbush It is intentional
– P__J__
Aug 2 '17 at 17:22
@NominalAnimal No, that wouldn't be valid, because that wouldn't work in#if
expressions.
– user743382
Aug 2 '17 at 17:48
|
show 1 more comment
up vote
7
down vote
favorite
up vote
7
down vote
favorite
7.20.4.1 Macros for minimum-width integer constants
... The macroUINTN_C(value)
shall expand to an integer constant expression corresponding to the typeuint_leastN_t
. For example, ifuint_least64_t
is a name for the typeunsigned long long int
, thenUINT64_C(0x123
) might expand to the integer constant0x123ULL
. C11dr §7.20.4.1 1
The type of UINTN_C()
and friends are not as expected. See "Expected" comments in code output.
A) Is my compiler implementation wrong and the constant type should be uint_leastN_t
?
or
B) Should the type of constant from UINTN_C(value)
be the minimum of uint_leastN_t
, int
, unsigned
and type needed to encode the value?
or
C) something else?
I had expected that the type of the constants to correspond to uint_leastN_t
, but it appears to not be so under 2 conditions:
**1 If the macro corresponding type is below int/unsigned
, the constant is int/unsigned
**2 If the value exceeds the range of the uint_leastN_t
, then the type becomes a wider type constant.
§6.4.4.1 "The type of an integer constant is the first of the corresponding list in which its value can be represented ... (long list follows).
#include <limits.h>
#include <stdio.h>
#define type_of(X) _Generic((X),
unsigned long long: "unsigned long long",
unsigned long: "unsigned long",
unsigned: "unsigned",
int: "int",
unsigned short: "unsigned short",
default: "?"
)
int main() {
uint_least16_t u16 = 0;
uint_least32_t u32 = 0;
uint_least64_t u64 = 0;
printf("%zu %sn", sizeof(u16), type_of(u16));
printf("%zu %sn", sizeof(u32), type_of(u32));
printf("%zu %sn", sizeof(u64), type_of(u64));
puts("");
printf("%zu %sn", sizeof((uint_least16_t) UINT16_C(0)), type_of((uint_least16_t) UINT16_C(0)));
printf("%zu %sn", sizeof UINT16_C(0), type_of(UINT16_C(0)));
printf("%zu %sn", sizeof UINT16_C(0x1234), type_of(UINT16_C(0x1234)));
printf("%zu %sn", sizeof UINT16_C(0x12345), type_of(UINT16_C(0x12345)));
printf("%zu %sn", sizeof UINT32_C(0x12345678), type_of(UINT32_C(0x12345678)));
printf("%zu %sn", sizeof UINT32_C(0x123456789), type_of(UINT32_C(0x123456789)));
return 0;
//round_frac_test(-2.05446162500000000e+06, 205);
round_frac_test(fp_rand(), 6);
round_frac_tests(10000);
puts("Done");
return 0;
}
Output
2 unsigned short
4 unsigned
8 unsigned long long
2 unsigned short
4 int // Expected 2 unsigned short, see **1
4 int // Expected 2 unsigned short, see **1
4 int // Expected 2 unsigned short, see **2
4 unsigned
8 unsigned long long // Expected 4 unsigned, see **2
I am using (GNU C11 (GCC) version 5.4.0)
In forming this post, I am leaning toward B, yet I am looking for your rational for confirmation -one way of the other. If B is so, a disappointing part is that UINTN_C()
could result in a signed type.
I suppose that is what the "minimum-width" part is about.
c language-lawyer
7.20.4.1 Macros for minimum-width integer constants
... The macroUINTN_C(value)
shall expand to an integer constant expression corresponding to the typeuint_leastN_t
. For example, ifuint_least64_t
is a name for the typeunsigned long long int
, thenUINT64_C(0x123
) might expand to the integer constant0x123ULL
. C11dr §7.20.4.1 1
The type of UINTN_C()
and friends are not as expected. See "Expected" comments in code output.
A) Is my compiler implementation wrong and the constant type should be uint_leastN_t
?
or
B) Should the type of constant from UINTN_C(value)
be the minimum of uint_leastN_t
, int
, unsigned
and type needed to encode the value?
or
C) something else?
I had expected that the type of the constants to correspond to uint_leastN_t
, but it appears to not be so under 2 conditions:
**1 If the macro corresponding type is below int/unsigned
, the constant is int/unsigned
**2 If the value exceeds the range of the uint_leastN_t
, then the type becomes a wider type constant.
§6.4.4.1 "The type of an integer constant is the first of the corresponding list in which its value can be represented ... (long list follows).
#include <limits.h>
#include <stdio.h>
#define type_of(X) _Generic((X),
unsigned long long: "unsigned long long",
unsigned long: "unsigned long",
unsigned: "unsigned",
int: "int",
unsigned short: "unsigned short",
default: "?"
)
int main() {
uint_least16_t u16 = 0;
uint_least32_t u32 = 0;
uint_least64_t u64 = 0;
printf("%zu %sn", sizeof(u16), type_of(u16));
printf("%zu %sn", sizeof(u32), type_of(u32));
printf("%zu %sn", sizeof(u64), type_of(u64));
puts("");
printf("%zu %sn", sizeof((uint_least16_t) UINT16_C(0)), type_of((uint_least16_t) UINT16_C(0)));
printf("%zu %sn", sizeof UINT16_C(0), type_of(UINT16_C(0)));
printf("%zu %sn", sizeof UINT16_C(0x1234), type_of(UINT16_C(0x1234)));
printf("%zu %sn", sizeof UINT16_C(0x12345), type_of(UINT16_C(0x12345)));
printf("%zu %sn", sizeof UINT32_C(0x12345678), type_of(UINT32_C(0x12345678)));
printf("%zu %sn", sizeof UINT32_C(0x123456789), type_of(UINT32_C(0x123456789)));
return 0;
//round_frac_test(-2.05446162500000000e+06, 205);
round_frac_test(fp_rand(), 6);
round_frac_tests(10000);
puts("Done");
return 0;
}
Output
2 unsigned short
4 unsigned
8 unsigned long long
2 unsigned short
4 int // Expected 2 unsigned short, see **1
4 int // Expected 2 unsigned short, see **1
4 int // Expected 2 unsigned short, see **2
4 unsigned
8 unsigned long long // Expected 4 unsigned, see **2
I am using (GNU C11 (GCC) version 5.4.0)
In forming this post, I am leaning toward B, yet I am looking for your rational for confirmation -one way of the other. If B is so, a disappointing part is that UINTN_C()
could result in a signed type.
I suppose that is what the "minimum-width" part is about.
c language-lawyer
c language-lawyer
asked Aug 2 '17 at 16:46
chux
78.8k869144
78.8k869144
1
I think you have a very valid point. The glibc macros instdint.h
should be e.g.#define UINT16_C(c) ((uint16_t)(c))
and so on, whereas right now they are just#define UINT16_C(c) c
(orc # U
,c # UL
,c # ULL
for larger types). Care to file a bug report? It usually only takes about a year for a tested patch to be accepted, and another year or so to dribble down to Linux distributions, in my experience.
– Nominal Animal
Aug 2 '17 at 17:14
1
Could this hinge on the corresponding in "shall expand to an integer constant expression corresponding to the typeuint_leastN_t
." In §6.2.5 6 there is "For each of the signed integer types, there is a corresponding (but different) unsigned integer type"; that is, maybe a type corresponding to an unsigned integer type need not be unsigned?
– David Bowling
Aug 2 '17 at 17:20
MSVC isn't much better:#define UINT16_C(x) (x)
– dbush
Aug 2 '17 at 17:22
@dbush It is intentional
– P__J__
Aug 2 '17 at 17:22
@NominalAnimal No, that wouldn't be valid, because that wouldn't work in#if
expressions.
– user743382
Aug 2 '17 at 17:48
|
show 1 more comment
1
I think you have a very valid point. The glibc macros instdint.h
should be e.g.#define UINT16_C(c) ((uint16_t)(c))
and so on, whereas right now they are just#define UINT16_C(c) c
(orc # U
,c # UL
,c # ULL
for larger types). Care to file a bug report? It usually only takes about a year for a tested patch to be accepted, and another year or so to dribble down to Linux distributions, in my experience.
– Nominal Animal
Aug 2 '17 at 17:14
1
Could this hinge on the corresponding in "shall expand to an integer constant expression corresponding to the typeuint_leastN_t
." In §6.2.5 6 there is "For each of the signed integer types, there is a corresponding (but different) unsigned integer type"; that is, maybe a type corresponding to an unsigned integer type need not be unsigned?
– David Bowling
Aug 2 '17 at 17:20
MSVC isn't much better:#define UINT16_C(x) (x)
– dbush
Aug 2 '17 at 17:22
@dbush It is intentional
– P__J__
Aug 2 '17 at 17:22
@NominalAnimal No, that wouldn't be valid, because that wouldn't work in#if
expressions.
– user743382
Aug 2 '17 at 17:48
1
1
I think you have a very valid point. The glibc macros in
stdint.h
should be e.g. #define UINT16_C(c) ((uint16_t)(c))
and so on, whereas right now they are just #define UINT16_C(c) c
(or c # U
, c # UL
, c # ULL
for larger types). Care to file a bug report? It usually only takes about a year for a tested patch to be accepted, and another year or so to dribble down to Linux distributions, in my experience.– Nominal Animal
Aug 2 '17 at 17:14
I think you have a very valid point. The glibc macros in
stdint.h
should be e.g. #define UINT16_C(c) ((uint16_t)(c))
and so on, whereas right now they are just #define UINT16_C(c) c
(or c # U
, c # UL
, c # ULL
for larger types). Care to file a bug report? It usually only takes about a year for a tested patch to be accepted, and another year or so to dribble down to Linux distributions, in my experience.– Nominal Animal
Aug 2 '17 at 17:14
1
1
Could this hinge on the corresponding in "shall expand to an integer constant expression corresponding to the type
uint_leastN_t
." In §6.2.5 6 there is "For each of the signed integer types, there is a corresponding (but different) unsigned integer type"; that is, maybe a type corresponding to an unsigned integer type need not be unsigned?– David Bowling
Aug 2 '17 at 17:20
Could this hinge on the corresponding in "shall expand to an integer constant expression corresponding to the type
uint_leastN_t
." In §6.2.5 6 there is "For each of the signed integer types, there is a corresponding (but different) unsigned integer type"; that is, maybe a type corresponding to an unsigned integer type need not be unsigned?– David Bowling
Aug 2 '17 at 17:20
MSVC isn't much better:
#define UINT16_C(x) (x)
– dbush
Aug 2 '17 at 17:22
MSVC isn't much better:
#define UINT16_C(x) (x)
– dbush
Aug 2 '17 at 17:22
@dbush It is intentional
– P__J__
Aug 2 '17 at 17:22
@dbush It is intentional
– P__J__
Aug 2 '17 at 17:22
@NominalAnimal No, that wouldn't be valid, because that wouldn't work in
#if
expressions.– user743382
Aug 2 '17 at 17:48
@NominalAnimal No, that wouldn't be valid, because that wouldn't work in
#if
expressions.– user743382
Aug 2 '17 at 17:48
|
show 1 more comment
2 Answers
2
active
oldest
votes
up vote
11
down vote
accepted
This is covered in the parent subsection, 7.20.4.
In the portion you quoted:
The macro
UINTN_C(value)
shall expand to an integer constant expression corresponding to the typeuint_leastN_t
.
it says "corresponding to", not that the expansion is actually of that type. The meaning of "corresponding to" is explained in 7.20.4p3:
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.
Since the macros are intended to be used in an #if
directive, they cannot use casts (the preprocessor doesn't understand casts or type names).
In practice, such a constant expression will almost always be implicitly converted to the appropriate type, so the fact that its actual type differs from what you might expect is not generally a problem.
As for a value outside the range of uint_leastN_t
, that's also covered in the parent subsection, in 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.
This is a "shall" outside a constraint, so violating it causes undefined behavior. Don't do that.
(When reading the C standard, it's generally a good idea to check the parent subsections for wording that might clarify or override what you're reading. I've been bitten by this myself.)
The "The type of the expression shall have the same type as would an expression of the corresponding type converted according to the integer promotions. " certainly explains the "**1" of the question.
– chux
Aug 2 '17 at 17:48
... and 7.20.4p2: explains "**2". Hmmm " check the parent" sounds like advice of years ago.
– chux
Aug 2 '17 at 18:02
add a comment |
up vote
0
down vote
On the host with 16 bit short
and 32 bit integers unsigned short
numbers are promoted to int
. So the those macros are defined as:
#define INT16_C(x) (x)
#define UINT16_C(x) (x)
with no 'U' suffix for the unsigned short
If an int can represent all values of the original type (as restricted
by the width, for a bit-field), the value is converted to an int;
Those macros do only expand to the corresponding constants (or integer literals using more common language), and do not create any objects, and have to usable in the #if. So no casts are allowed. Macros do not perform any range checks as well.
int16_t x0 = 123;
uint16_t x1 = 123; // no sign suffix needed
int32_t x2 = 2147483647;
uint32_t x3 = 2147583647U; //sign suffix theoreticaly needed as int and unsigned int have the same rank
int64_t x4 = 9223372036854775807LL;
uint64_t x5 = 9237372036854775807ULL; //same as above
Where is your quote from? I’m surprised that conversion happens for constants.
– Daniel H
Aug 2 '17 at 17:45
'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.' And then it is from the integer promotion rules. I hope that is enough
– P__J__
Aug 2 '17 at 17:49
Yeah, that’s the relevant part I was missing.
– Daniel H
Aug 2 '17 at 18:04
add a comment |
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
11
down vote
accepted
This is covered in the parent subsection, 7.20.4.
In the portion you quoted:
The macro
UINTN_C(value)
shall expand to an integer constant expression corresponding to the typeuint_leastN_t
.
it says "corresponding to", not that the expansion is actually of that type. The meaning of "corresponding to" is explained in 7.20.4p3:
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.
Since the macros are intended to be used in an #if
directive, they cannot use casts (the preprocessor doesn't understand casts or type names).
In practice, such a constant expression will almost always be implicitly converted to the appropriate type, so the fact that its actual type differs from what you might expect is not generally a problem.
As for a value outside the range of uint_leastN_t
, that's also covered in the parent subsection, in 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.
This is a "shall" outside a constraint, so violating it causes undefined behavior. Don't do that.
(When reading the C standard, it's generally a good idea to check the parent subsections for wording that might clarify or override what you're reading. I've been bitten by this myself.)
The "The type of the expression shall have the same type as would an expression of the corresponding type converted according to the integer promotions. " certainly explains the "**1" of the question.
– chux
Aug 2 '17 at 17:48
... and 7.20.4p2: explains "**2". Hmmm " check the parent" sounds like advice of years ago.
– chux
Aug 2 '17 at 18:02
add a comment |
up vote
11
down vote
accepted
This is covered in the parent subsection, 7.20.4.
In the portion you quoted:
The macro
UINTN_C(value)
shall expand to an integer constant expression corresponding to the typeuint_leastN_t
.
it says "corresponding to", not that the expansion is actually of that type. The meaning of "corresponding to" is explained in 7.20.4p3:
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.
Since the macros are intended to be used in an #if
directive, they cannot use casts (the preprocessor doesn't understand casts or type names).
In practice, such a constant expression will almost always be implicitly converted to the appropriate type, so the fact that its actual type differs from what you might expect is not generally a problem.
As for a value outside the range of uint_leastN_t
, that's also covered in the parent subsection, in 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.
This is a "shall" outside a constraint, so violating it causes undefined behavior. Don't do that.
(When reading the C standard, it's generally a good idea to check the parent subsections for wording that might clarify or override what you're reading. I've been bitten by this myself.)
The "The type of the expression shall have the same type as would an expression of the corresponding type converted according to the integer promotions. " certainly explains the "**1" of the question.
– chux
Aug 2 '17 at 17:48
... and 7.20.4p2: explains "**2". Hmmm " check the parent" sounds like advice of years ago.
– chux
Aug 2 '17 at 18:02
add a comment |
up vote
11
down vote
accepted
up vote
11
down vote
accepted
This is covered in the parent subsection, 7.20.4.
In the portion you quoted:
The macro
UINTN_C(value)
shall expand to an integer constant expression corresponding to the typeuint_leastN_t
.
it says "corresponding to", not that the expansion is actually of that type. The meaning of "corresponding to" is explained in 7.20.4p3:
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.
Since the macros are intended to be used in an #if
directive, they cannot use casts (the preprocessor doesn't understand casts or type names).
In practice, such a constant expression will almost always be implicitly converted to the appropriate type, so the fact that its actual type differs from what you might expect is not generally a problem.
As for a value outside the range of uint_leastN_t
, that's also covered in the parent subsection, in 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.
This is a "shall" outside a constraint, so violating it causes undefined behavior. Don't do that.
(When reading the C standard, it's generally a good idea to check the parent subsections for wording that might clarify or override what you're reading. I've been bitten by this myself.)
This is covered in the parent subsection, 7.20.4.
In the portion you quoted:
The macro
UINTN_C(value)
shall expand to an integer constant expression corresponding to the typeuint_leastN_t
.
it says "corresponding to", not that the expansion is actually of that type. The meaning of "corresponding to" is explained in 7.20.4p3:
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.
Since the macros are intended to be used in an #if
directive, they cannot use casts (the preprocessor doesn't understand casts or type names).
In practice, such a constant expression will almost always be implicitly converted to the appropriate type, so the fact that its actual type differs from what you might expect is not generally a problem.
As for a value outside the range of uint_leastN_t
, that's also covered in the parent subsection, in 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.
This is a "shall" outside a constraint, so violating it causes undefined behavior. Don't do that.
(When reading the C standard, it's generally a good idea to check the parent subsections for wording that might clarify or override what you're reading. I've been bitten by this myself.)
edited Nov 10 at 22:38
answered Aug 2 '17 at 17:44
Keith Thompson
188k25272465
188k25272465
The "The type of the expression shall have the same type as would an expression of the corresponding type converted according to the integer promotions. " certainly explains the "**1" of the question.
– chux
Aug 2 '17 at 17:48
... and 7.20.4p2: explains "**2". Hmmm " check the parent" sounds like advice of years ago.
– chux
Aug 2 '17 at 18:02
add a comment |
The "The type of the expression shall have the same type as would an expression of the corresponding type converted according to the integer promotions. " certainly explains the "**1" of the question.
– chux
Aug 2 '17 at 17:48
... and 7.20.4p2: explains "**2". Hmmm " check the parent" sounds like advice of years ago.
– chux
Aug 2 '17 at 18:02
The "The type of the expression shall have the same type as would an expression of the corresponding type converted according to the integer promotions. " certainly explains the "**1" of the question.
– chux
Aug 2 '17 at 17:48
The "The type of the expression shall have the same type as would an expression of the corresponding type converted according to the integer promotions. " certainly explains the "**1" of the question.
– chux
Aug 2 '17 at 17:48
... and 7.20.4p2: explains "**2". Hmmm " check the parent" sounds like advice of years ago.
– chux
Aug 2 '17 at 18:02
... and 7.20.4p2: explains "**2". Hmmm " check the parent" sounds like advice of years ago.
– chux
Aug 2 '17 at 18:02
add a comment |
up vote
0
down vote
On the host with 16 bit short
and 32 bit integers unsigned short
numbers are promoted to int
. So the those macros are defined as:
#define INT16_C(x) (x)
#define UINT16_C(x) (x)
with no 'U' suffix for the unsigned short
If an int can represent all values of the original type (as restricted
by the width, for a bit-field), the value is converted to an int;
Those macros do only expand to the corresponding constants (or integer literals using more common language), and do not create any objects, and have to usable in the #if. So no casts are allowed. Macros do not perform any range checks as well.
int16_t x0 = 123;
uint16_t x1 = 123; // no sign suffix needed
int32_t x2 = 2147483647;
uint32_t x3 = 2147583647U; //sign suffix theoreticaly needed as int and unsigned int have the same rank
int64_t x4 = 9223372036854775807LL;
uint64_t x5 = 9237372036854775807ULL; //same as above
Where is your quote from? I’m surprised that conversion happens for constants.
– Daniel H
Aug 2 '17 at 17:45
'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.' And then it is from the integer promotion rules. I hope that is enough
– P__J__
Aug 2 '17 at 17:49
Yeah, that’s the relevant part I was missing.
– Daniel H
Aug 2 '17 at 18:04
add a comment |
up vote
0
down vote
On the host with 16 bit short
and 32 bit integers unsigned short
numbers are promoted to int
. So the those macros are defined as:
#define INT16_C(x) (x)
#define UINT16_C(x) (x)
with no 'U' suffix for the unsigned short
If an int can represent all values of the original type (as restricted
by the width, for a bit-field), the value is converted to an int;
Those macros do only expand to the corresponding constants (or integer literals using more common language), and do not create any objects, and have to usable in the #if. So no casts are allowed. Macros do not perform any range checks as well.
int16_t x0 = 123;
uint16_t x1 = 123; // no sign suffix needed
int32_t x2 = 2147483647;
uint32_t x3 = 2147583647U; //sign suffix theoreticaly needed as int and unsigned int have the same rank
int64_t x4 = 9223372036854775807LL;
uint64_t x5 = 9237372036854775807ULL; //same as above
Where is your quote from? I’m surprised that conversion happens for constants.
– Daniel H
Aug 2 '17 at 17:45
'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.' And then it is from the integer promotion rules. I hope that is enough
– P__J__
Aug 2 '17 at 17:49
Yeah, that’s the relevant part I was missing.
– Daniel H
Aug 2 '17 at 18:04
add a comment |
up vote
0
down vote
up vote
0
down vote
On the host with 16 bit short
and 32 bit integers unsigned short
numbers are promoted to int
. So the those macros are defined as:
#define INT16_C(x) (x)
#define UINT16_C(x) (x)
with no 'U' suffix for the unsigned short
If an int can represent all values of the original type (as restricted
by the width, for a bit-field), the value is converted to an int;
Those macros do only expand to the corresponding constants (or integer literals using more common language), and do not create any objects, and have to usable in the #if. So no casts are allowed. Macros do not perform any range checks as well.
int16_t x0 = 123;
uint16_t x1 = 123; // no sign suffix needed
int32_t x2 = 2147483647;
uint32_t x3 = 2147583647U; //sign suffix theoreticaly needed as int and unsigned int have the same rank
int64_t x4 = 9223372036854775807LL;
uint64_t x5 = 9237372036854775807ULL; //same as above
On the host with 16 bit short
and 32 bit integers unsigned short
numbers are promoted to int
. So the those macros are defined as:
#define INT16_C(x) (x)
#define UINT16_C(x) (x)
with no 'U' suffix for the unsigned short
If an int can represent all values of the original type (as restricted
by the width, for a bit-field), the value is converted to an int;
Those macros do only expand to the corresponding constants (or integer literals using more common language), and do not create any objects, and have to usable in the #if. So no casts are allowed. Macros do not perform any range checks as well.
int16_t x0 = 123;
uint16_t x1 = 123; // no sign suffix needed
int32_t x2 = 2147483647;
uint32_t x3 = 2147583647U; //sign suffix theoreticaly needed as int and unsigned int have the same rank
int64_t x4 = 9223372036854775807LL;
uint64_t x5 = 9237372036854775807ULL; //same as above
edited Aug 2 '17 at 17:54
answered Aug 2 '17 at 17:21
P__J__
1
1
Where is your quote from? I’m surprised that conversion happens for constants.
– Daniel H
Aug 2 '17 at 17:45
'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.' And then it is from the integer promotion rules. I hope that is enough
– P__J__
Aug 2 '17 at 17:49
Yeah, that’s the relevant part I was missing.
– Daniel H
Aug 2 '17 at 18:04
add a comment |
Where is your quote from? I’m surprised that conversion happens for constants.
– Daniel H
Aug 2 '17 at 17:45
'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.' And then it is from the integer promotion rules. I hope that is enough
– P__J__
Aug 2 '17 at 17:49
Yeah, that’s the relevant part I was missing.
– Daniel H
Aug 2 '17 at 18:04
Where is your quote from? I’m surprised that conversion happens for constants.
– Daniel H
Aug 2 '17 at 17:45
Where is your quote from? I’m surprised that conversion happens for constants.
– Daniel H
Aug 2 '17 at 17:45
'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.' And then it is from the integer promotion rules. I hope that is enough
– P__J__
Aug 2 '17 at 17:49
'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.' And then it is from the integer promotion rules. I hope that is enough
– P__J__
Aug 2 '17 at 17:49
Yeah, that’s the relevant part I was missing.
– Daniel H
Aug 2 '17 at 18:04
Yeah, that’s the relevant part I was missing.
– Daniel H
Aug 2 '17 at 18:04
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%2f45466601%2funexpected-types-from-uint32-c-uintn-c%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
1
I think you have a very valid point. The glibc macros in
stdint.h
should be e.g.#define UINT16_C(c) ((uint16_t)(c))
and so on, whereas right now they are just#define UINT16_C(c) c
(orc # U
,c # UL
,c # ULL
for larger types). Care to file a bug report? It usually only takes about a year for a tested patch to be accepted, and another year or so to dribble down to Linux distributions, in my experience.– Nominal Animal
Aug 2 '17 at 17:14
1
Could this hinge on the corresponding in "shall expand to an integer constant expression corresponding to the type
uint_leastN_t
." In §6.2.5 6 there is "For each of the signed integer types, there is a corresponding (but different) unsigned integer type"; that is, maybe a type corresponding to an unsigned integer type need not be unsigned?– David Bowling
Aug 2 '17 at 17:20
MSVC isn't much better:
#define UINT16_C(x) (x)
– dbush
Aug 2 '17 at 17:22
@dbush It is intentional
– P__J__
Aug 2 '17 at 17:22
@NominalAnimal No, that wouldn't be valid, because that wouldn't work in
#if
expressions.– user743382
Aug 2 '17 at 17:48