【发布时间】:2018-09-26 07:27:53
【问题描述】:
在常量上使用文字后缀有什么区别:
#define MY_LONG 0x1UL
并转换一个常量:
#define MY_LONG (unsigned long)0x1
什么时候选择前者,什么时候选择后者?
【问题讨论】:
标签: c
在常量上使用文字后缀有什么区别:
#define MY_LONG 0x1UL
并转换一个常量:
#define MY_LONG (unsigned long)0x1
什么时候选择前者,什么时候选择后者?
【问题讨论】:
标签: c
在常量上使用文字后缀:...和强制转换常量:有什么区别?
让我们尝试使用 2 个定义作为预处理器控制。预处理器数学不理解各种类型的宽度。作为令牌处理的一部分:
出于此令牌转换和评估的目的,所有有符号整数类型和所有无符号整数类型的行为就像它们分别具有与
intmax_t和uintmax_t类型相同的表示形式... C11dr §6.10。 1 4
#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 确保某些无符号 类型,L 确保至少 long。
#define MY_LONG 0x123456789UL
强制转换可以改变值。在下面的这种情况下,值变为 0x23456789 并键入 unsigned long
#define MY_LONG (unsigned long)0x123456789
什么时候选择前者,什么时候选择后者?
L 微调类型至少为 long,强制转换强制类型为 long。
当MY_LONG 应至少为long 或该值较小时使用L,在long [-2147483647 ... 2147483647] 的最小 范围内 p>
如果宏可以与预处理一起使用,请不要使用强制转换。
否则使用强制转换(long) 来强制执行long。 IMO,这很少是目标。一个例外是常量必须是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],但仍然是用 () 包围宏的好习惯,除非评估问题的可能性为零。
【讨论】:
没有实际区别,这些是 100% 等效的。
唯一形式上的区别是UL 是整数常量的一部分,而强制类型转换可以放在任何表达式之前,包括运行时计算的表达式。
UL 的主要原因是在重要的地方强制使用整数常量类型。它通常比演员表更具可读性。示例:1UL << n 与 (unsigned long)1 << n。
另一方面,强制转换具有更广泛的用途,因为它们不仅可用于在编译时强制类型,还可以在运行时触发类型转换。
【讨论】:
绝对没有区别。两者都是具有相同值和类型的编译时可评估常量表达式,尽管将第二个版本写为((unsigned long)0x1) 可能是明智之举。
我个人会选择第一个,因为它更清晰;至少在我看来,演员表是 run-time 运算符,而不是 compile-time 运算符。
【讨论】:
for 循环甚至switch 块中提出类似的批评。
gotoftw! ;-p
两者之间几乎没有区别:它们都是常量表达式,值为1,类型为unsigned long。
一个显着的区别是你可以使用0x1UL作为预处理器测试表达式的一部分,但你不能使用(unsigned long)1:
#include <stdio.h>
#if 0x1UL
int main() {
return 0;
}
#else
#error 0x1UL should be true
#endif
【讨论】:
从技术上讲,有一种方法可以区分它们,但你真的必须非常努力:
char a [10];
printf( "size is %zu\n", sizeof(MY_LONG [a]) );
在上面的示例中,文字 (0x1UL) 版本将让数组以 unsigned long 文字作为索引,产生 1,因为它是 sizeof(char)。转换版本将使数组以int 文字作为索引,然后将生成的字符转换为unsigned long,然后再将其传递给sizeof()。 sizeof(unsigned long) 通常是 8。
这是因为索引运算符 [] 的排名高于强制转换运算符 ()。
【讨论】: