c - 来自 UINT32_C、UINTN_C 的意外类型

标签 c language-lawyer

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

UINTN_C() 的类型和友元不符合预期。请参阅代码输出中的“预期”注释。

A) 是不是我的编译器实现有误,常量类型应该是uint_leastN_t
或者
B) UINTN_C(value) 中的常量类型是否应该是 uint_leastN_tintunsigned 和编码值所需的类型?
或者
C)还有什么?


我曾期望常量的类型对应于uint_leastN_t,但在两种情况下似乎并非如此:

**1 如果宏对应类型在int/unsigned以下,常量为int/unsigned

**2 如果该值超出uint_leastN_t 的范围,则该类型变为更宽的类型常量。

§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;
}

输出

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

我正在使用(GNU C11 (GCC) 版本 5.4.0)

在撰写这篇文章时,我倾向于 B,但我正在寻找您的确认理由 - 一种方式。如果 B 是这样,一个令人失望的部分是 UINTN_C() 可能导致 signed 类型。

我想这就是“最小宽度”部分的内容。

最佳答案

父小节 7.20.4 对此进行了介绍。

在你引用的部分:

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

它说“对应于”,并不是说扩展实际上是那种类型。 “对应于”的含义在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.

由于宏旨在用于 #if 指令,因此它们不能使用强制转换(预处理器不理解强制转换或类型名称)。

在实践中,这样的常量表达式几乎总是会隐式转换为适当的类型,因此它的实际类型与您可能期望的不同这一事实通常不是问题。

至于 uint_leastN_t 范围之外的值,在 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.

这是约束之外的“应该”,因此违反它会导致未定义的行为。不要那样做。

(在阅读 C 标准时,通常最好检查父小节中可能澄清或覆盖您正在阅读的内容的措辞。我自己也被这个困扰。)

关于c - 来自 UINT32_C、UINTN_C 的意外类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45466601/

相关文章:

c - 死锁预防,随机线程执行顺序C

c - 外部变量是如何定义的?

c - gdb 按行号反汇编

c++ - gcc 和 clang 在使用无符号值左移时产生不同的输出

java - Stream.sorted().forEach() 是否按预期工作?

c++ - 用基数排序实现 std::sort 的重载是否合法?

c - 是否为定义明确的同一文件描述符创建两个文件?

在 C 中创建自己的头文件

c - C 中的 OR 运算符

c++ - 读取未初始化的变量