在常量上使用文字后缀有何区别:
#define MY_LONG 0x1UL
并投射一个常量:
#define MY_LONG (unsigned long)0x1
您何时选择前者,何时选择后者?
答案 0 :(得分:8)
在常量...上使用文字后缀与强制转换常量有什么区别??
让我们尝试使用2定义作为预处理程序控制。预处理器数学无法理解各种类型的宽度。作为令牌处理的一部分:
出于此令牌转换和评估的目的,所有有符号整数类型和所有无符号整数类型的行为就像它们分别与类型
intmax_t
和uintmax_t
具有相同的表示形式一样。 C11dr§6.10.14
#define MY_LONG1 0x123456789UL
#define MY_LONG2 (unsigned long)0x123456789
int main(void) {
#if MY_LONG1 == 0x123456789u
puts("MY_LONG1 == 0x123456789u");
#endif
#if MY_LONG2 == 0x123456789u
puts("MY_LONG2 == 0x123456789u");
#endif
}
#if MY_LONG2 == 0x123456789u
产生compiler error。
error: missing binary operator before token "long"
#define MY_LONG2 (unsigned long)0x123456789
请注意:L
对预处理没有任何作用。
注意:U
确实可以进行预处理。
值为1,没有区别。
但是,如果值超过ULONG_MAX
(例如32位),则下面的内容为unsigned long long
。 U
确保某些 unsigned 类型,L
确保至少 long
。
#define MY_LONG 0x123456789UL
强制转换可以更改值。在下面的这种情况下,该值变为0x23456789并键入unsigned long
#define MY_LONG (unsigned long)0x123456789
您何时选择前者,何时选择后者?
L
将类型微调为至少long
,强制类型转换为long
。
在L
的最小范围内,当MY_LONG
应该至少为long
或值很小时,请使用long
。 2147483647 ... 2147483647]
如果宏可以与预处理一起使用,请不要使用强制转换。
否则,使用强制转换(long)
强制执行long
。海事组织,这很少是目标。如果常量无论其值如何都必须为unsigned long
,则为例外。
// Works well if unsigned long is 64-bit or less
#define MY_ULONG_EVERY_OTHER_BIT ((unsigned long) 0xAAAAAAAAAAAAAAAAu)
注意:通常,我避免在常量中使用L
,而让实现确定类型。
以下内容将是unsigned, unsigned long , unsigned long long
中最窄的类型。附加L
将适合最窄的unsigned long, unsigned long long
。
#define MY_BIGU 0x123456789u
OP的定义存在一个细微的问题。
#define MY_LONG (unsigned long)0x1
应该如下以确保紧密粘合。
#define MY_LONG ((unsigned long)0x1)
只有少数几个运算符具有更高的优先级,它们可能会使代码混乱。病理,例如:MY_LONG[a]
应该是(unsigned long)(0x1[a])
而不是((unsigned long)0x1)[a]
,但是仍然是将宏用()
括起来的良好实践,除非评估问题的机会为零。
答案 1 :(得分:5)
没有实际差异,它们是100%等效的。
唯一的形式差异是UL
是整数常量的一部分,而强制转换可以放在任何表达式的前面,包括运行时评估的表达式。
UL的主要原因是在重要的地方强制使用整数常量的类型。它通常比强制转换更具可读性。示例:1UL << n
与(unsigned long)1 << n
。
另一方面,Cast具有更广泛的用途,因为它们不仅可以用于在编译时强制类型,还可以在运行时触发类型转换。
答案 2 :(得分:3)
绝对没有区别。两者都是具有相同值和类型的可编译时评估的常量表达式,尽管您明智的做法是将第二个版本写为((unsigned long)0x1)
。
我个人会选择第一个,因为它更清晰;至少在我看来,强制类型转换是运行时运算符,而不是编译时运算符。
答案 3 :(得分:1)
两者之间几乎没有什么区别:它们都是常数表达式,其值为1
,类型为unsigned long
。
一个显着的区别是您可以将0x1UL
用作预处理程序测试表达式的一部分,但不能使用(unsigned long)1
:
#include <stdio.h>
#if 0x1UL
int main() {
return 0;
}
#else
#error 0x1UL should be true
#endif
答案 4 :(得分:0)
从技术上讲,有一种方法可以在它们之间进行区分,但是您确实必须非常努力:
char a [10];
printf( "size is %zu\n", sizeof(MY_LONG [a]) );
在上面的示例中,文字(0x1UL
)版本将使数组以unsigned long
文字作为索引,并产生1
,因为它是sizeof(char)
。强制转换版本将使数组以int
文字作为索引,然后将生成的char强制转换为unsigned long
,然后将其传递给sizeof()
。 sizeof(unsigned long)
通常是8
。
这是因为索引运算符[]
的排名高于转换运算符()
。