来自一个例子
unsigned long x = 12345678UL
我们一直都知道编译器只需要看到" long"在上面的例子中设置4个字节(在32位)的内存。问题是为什么我们应该在长常量中使用L / UL,即使声明它很长。
答案 0 :(得分:56)
如果未使用后缀L
或UL
,编译器将使用可包含列表中常量的第一种类型(请参阅C99标准中的详细信息,第6.4.4节:5。列表为int
,long int
,long long int
)。
因此,大多数情况下,没有必要使用后缀。它不会改变程序的含义。对于大多数体系结构,它不会更改x
的示例初始化的含义,但如果您选择了无法表示为long long
的数字,则会更改它。另请参阅codebauer的答案,其中包含后缀U
部分的示例。
在程序员可能想要明确设置常量类型的情况下有几种情况。一个例子是使用可变参数函数时:
printf("%lld", 1LL); // correct, because 1LL has type long long
printf("%lld", 1); // undefined behavior, because 1 has type int
使用后缀的一个常见原因是确保计算结果不会溢出。两个例子是:
long x = 10000L * 4096L;
unsigned long long y = 1ULL << 36;
在两个示例中,没有后缀,常量将具有类型int
,并且计算将为int
。在每个例子中,这都会产生溢出的风险。使用后缀意味着计算将以更大的类型完成,而且具有足够的结果范围。
随着Orbit中的Lightness Races的出现,litteral的后缀在之前分配。在上面的两个示例中,仅将x
声明为long
而将y
声明为unsigned long long
不足以防止计算分配给它们的表达式中的溢出。
另一个例子是比较x < 12U
,其中变量x
的类型为int
。如果没有U
后缀,编译器会将常量12
键入int
,因此比较是对有符号整数的比较。
int x = -3;
printf("%d\n", x < 12); // prints 1 because it's true that -3 < 12
使用U
后缀,比较将成为无符号整数的比较。 “通常的算术转换”意味着-3被转换为大的无符号int:
printf("%d\n", x < 12U); // prints 0 because (unsigned int)-3 is large
事实上,常量的类型甚至可能会改变算术计算的结果,这也是因为“通常的算术转换”的工作方式。
请注意,对于十进制常量,C99建议的类型列表不包含unsigned long long
。在C90中,列表以当时最大的标准化无符号整数类型(unsigned long
)结束。结果是,通过向C99添加标准类型long long
来更改某些程序的含义:在C90中键入为unsigned long
的相同常量现在可以作为签名long long
键入代替。我相信这就是为什么在C99中,决定不在小数常量的类型列表中使用unsigned long long
。
有关示例,请参阅this和this博文。
答案 1 :(得分:8)
因为数字文字通常是int类型。 UL / L告诉编译器它们不是int类型,例如假设32位int和64位长
long i = 0xffff;
long j = 0xffffUL;
此处右侧的值必须转换为有符号长号(32位 - > 64位)
答案 2 :(得分:5)
问题是为什么我们应该在长常量中使用L / UL,即使声明它很长。
因为它不是“之后”;它是“之前”。
首先你有文字,然后它被转换成你试图挤压它的变量的类型。
答案 3 :(得分:0)
与此帖相关的是u
。
u
的一个原因是允许小数形式的整数常量大于LLONG_MAX
。
// Likely to generate a warning.
unsigned long long limit63bit = 18446744073709551615`; // 2^64 - 1
// OK
unsigned long long limit63bit = 18446744073709551615u`;