What is the purpose of “Macros for minimum-width integer constants”
在C99标准第7.18.4.1节"最小宽度整数常量的宏"中,一些定义为[U]INT[N]_C(x)的宏用于将常量整数转换为N = 8、16、32、64的最小数据类型。为什么这些宏自I 可以改用L,UL,LL或ULL修饰符? 例如,当我想使用至少32位无符号常量整数时,我可以简单地写42UL而不是UINT32_C(42)。 由于长数据类型至少为32位宽,因此它也是可移植的。
那么,这些宏的目的是什么?
-
我认为它们是为了让您不必担心在创建自己的固定大小的整数类型时int或long有多大。
您需要在想要确保它们不会变得太宽的地方使用它们
1
| #define myConstant UINT32_C(42) |
然后
1 2
| printf("%" PRId32 " is %s\
", (hasproperty ? toto : myConstant ),"rich"); |
在这里,如果常量为UL,则表达式可能为ulong,可变参数函数会将64位值放在栈中,而该值会被printf误解。
-
那么,您是否建议在某些32位平台上将long设置为64位?因此,在某些功能(如printf)中,这将是有问题的。如果是这样,这也会对性能产生影响,因为当32位足够时,就会进行64位整数操作。
-
是的,这取决于平台设计者的决定。并且不要高估针对不同宽度的整数进行运算的性能差异,在现代机器上,算术本身没有任何区别。唯一的区别可能是,如果您在循环中执行大量此类操作,并且对内存的访问将成为瓶颈。相反,现代avx处理器执行256位操作的速度与32位操作一样快,因此通常选择一个指定宽度的类型是个坏主意。使用size_t,ptrdiff_t以及类似您正在做的语义的事情。
-
是否有16位编译器的静态const uint32_t var = 0xFFFF0000;可能导致var = 0x0000? C99和C89规格说明了常量的大小?
-
@Samuel:不。常量始终具有适合它的类型。由于它的值适合32位,因此这里永远不会丢失信息。
-
这不是一个好例子。最小宽度的整数常量宏可能会添加一个整数常量后缀(例如L,LL,U,UL或ULL),但是不会像常规强制转换那样贬低该参数。您执行printf("%" PRIu32"\
", UINT32_C(42000000000));和bam,您的程序是未定义的。
-
@PSkocik,我没看到。确保如果您输入的常量不适合该类型,则该行为可能是不确定的。但是,不错的编译器对此有所警告,因此这是一个小问题。另一方面,如果您向下转换为该类型,则会得到另一个值,并且您的程序不正确,并且没有编译器会警告您。我更喜欢前者。
它们使用宽度至少为N的最小整数类型,因此UINT32_C(42)仅等效于int小于32位的系统上的42UL。在int为32位或更大的系统上,UINT32_C(42)等效于42U。您甚至可以想象一个short为32位宽的系统,在这种情况下UINT32_C(42)将等效于(unsigned short)42。
编辑:@obareey似乎大多数(如果不是全部)标准库的实现不符合标准的这一部分,也许是因为这是不可能的。 [glibc错误2841] [glibc提交b7398be5]
-
但是在那些平台上,是否32位短并不重要,因为它是至少32位的最快整数,或者我也这么认为。现在我很困惑。因为它在标准中写道"宏UINTN_C(value)应该扩展为与uint_leastN_t类型相对应的整数常量表达式",但是32位ARM编译器定义了" #define UINT8_C(x)(x ## u)"和" #define UINT16_C(x)(x ## u)",无需任何强制转换。
-
最小,不是最快。
-
我想知道这些宏中有多少实际被用来使代码更可移植的?有符号对无符号比较之类的事物的语义有很多奇怪而古怪的极端案例,我看不出有人会希望如何应对它们。例如,给定uint32_t n,如果n为零,(n-1) < UINT32_C(5);的行为是什么?如何最好地将该表达式写成在int大于,小于或等于32位的系统上可移植?
宏实际上可能会添加一个整数常量后缀,例如
L,LL,U,UL,o UL作为其参数,这基本上使它们几乎等同于相应的强制类型转换,只是后缀不会降低。
例如。,
LLP64体系结构上的UINT32_C(42000000000)(420亿)将变为42000000000U,其类型为UL,但要遵循此处说明的规则。另一方面,相应的强制转换((uint32_t)42000000000)会将其截断为uint32_t(在LLP64上为unsigned int)。
我想不出一个好用例,但我想它可以在某些需要至少X位才能工作的通用位旋转宏中使用,但是如果用户传入某些内容,则不想删除任何多余的位大。