繁体   English   中英

来自UINT32_C,UINTN_C的意外类型

[英]Unexpected types from UINT32_C, UINTN_C

7.20.4.1最小宽度整数常量的宏
...宏UINTN_C(value)应扩展为对应于uint_leastN_t类型的整数常量表达式。 例如,如果uint_least64_tunsigned long long int类型的名称,则UINT64_C(0x123 )可能会扩展为整数常量0x123ULL C11dr§7.20.4.11

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

A)我的编译器实现是错误的,常量类型应该是uint_leastN_t吗?
要么
B)来自UINTN_C(value)的常量类型是否应该是uint_leastN_tintunsigned和类型编码值所需的最小值?
要么
C)别的什么?


我原以为常量的类型对应于uint_leastN_t ,但在2个条件下似乎不是这样:

** 1如果宏对应的类型低于int/unsigned ,则常量为int/unsigned

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

§6.4.4.1“整数常量的类型是相应列表中可以表示其值的第一个...(后面是长列表)。


#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()可能导致签名类型。

我想这就是“最小宽度”部分的含义。

这一点在父节小节7.20.4中有所涉及。

在您引用的部分中:

UINTN_C(value)将扩展为对应于类型uint_leastN_t的整数常量表达式。

它说“ 对应于 ”,而不是扩展实际上那种类型。 对应于 ”的含义在7.20.4p3中解释:

其中一个宏的每次调用都应扩展为适合在#if预处理指令中使用的整数常量表达式。 表达式的类型应与根据整数提升转换的相应类型的表达式具有相同的类型。 表达式的值应该是参数的值。

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

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

至于uint_leastN_t范围之外的值,在7.20.4p2中也包含在父子小节中:

这些宏的任何实例中的参数都应是未填充的整数常量(如6.4.4.1中所定义),其值不超过相应类型的限制。

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

(在阅读C标准时,通常最好检查一下家长小节的措辞,这些措辞可能会澄清或覆盖您正在阅读的内容。我自己也被这个问题所困扰。)

在具有16位short整数和32位整数的主机上, unsigned short整数被提升为int 所以这些宏定义为:

#define INT16_C(x) (x)
#define UINT16_C(x) (x)

没有'U'后缀为unsigned short

如果int可以表示原始类型的所有值(由宽度限制,对于位字段),则该值将转换为int;

这些宏只扩展为相应的常量(或使用更常用语言的整数文字),并且不创建任何对象,并且必须在#if中使用。 所以不允许演员阵容。 宏也不执行任何范围检查。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM