Unexpected types from UINT32_C, UINTN_C

Viewed 588

7.20.4.1 Macros for minimum-width integer constants
... The macro UINTN_C(value) shall expand to an integer constant expression corresponding to the type uint_leastN_t. For example, if uint_least64_t is a name for the type unsigned long long int, then UINT64_C(0x123) might expand to the integer constant 0x123ULL. 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 %s\n", sizeof(u16), type_of(u16));
  printf("%zu %s\n", sizeof(u32), type_of(u32));
  printf("%zu %s\n", sizeof(u64), type_of(u64));
  puts("");
  printf("%zu %s\n", sizeof((uint_least16_t) UINT16_C(0)), type_of((uint_least16_t) UINT16_C(0)));
  printf("%zu %s\n", sizeof UINT16_C(0), type_of(UINT16_C(0)));
  printf("%zu %s\n", sizeof UINT16_C(0x1234), type_of(UINT16_C(0x1234)));
  printf("%zu %s\n", sizeof UINT16_C(0x12345), type_of(UINT16_C(0x12345)));
  printf("%zu %s\n", sizeof UINT32_C(0x12345678), type_of(UINT32_C(0x12345678)));
  printf("%zu %s\n", 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.

2 Answers
Related