从一个例子
unsigned long x = 12345678UL
Run Code Online (Sandbox Code Playgroud)
我们总是知道编译器需要在上面的例子中只看到"long"来设置4个字节(32位)的内存.问题是为什么我们应该在长常量中使用L/UL,即使在声明它很长之后也是如此.
Pas*_*uoq 61
当一个后缀L
或UL
没有被使用,则编译器使用可以包含恒定从列表中的第一类型(参见C99标准的细节,条款6.4.4:5对于十进制常量,该列表是int
,long int
,long long int
).
因此,大多数情况下,没有必要使用后缀.它不会改变程序的含义.它并没有改变x
大多数体系结构的示例初始化的含义,尽管如果你选择了一个无法表示为数字的数字long long
.有关U
后缀部分是必要的示例,请参阅codebauer的答案.
当程序员可能想要明确设置常量的类型时,有几种情况.一个例子是使用可变参数函数时:
printf("%lld", 1LL); // correct, because 1LL has type long long
printf("%lld", 1); // undefined behavior, because 1 has type int
Run Code Online (Sandbox Code Playgroud)
使用后缀的一个常见原因是确保计算结果不会溢出.两个例子是:
long x = 10000L * 4096L;
unsigned long long y = 1ULL << 36;
Run Code Online (Sandbox Code Playgroud)
在两个示例中,没有后缀,常量将具有类型int
,并且计算将被制作为int
.在每个例子中,这都会产生溢出的风险.使用后缀意味着计算将以更大的类型完成,其具有足够的结果范围.
正如Orbit中的Lightness Races所说,litteral的后缀出现在任务之前.在上面的两个例子中,简单地声明x
as long
和y
as unsigned long long
不足以防止分配给它们的表达式的计算中的溢出.
另一个例子是x < 12U
变量x
具有类型的比较int
.如果没有U
后缀,编译器会将常量键入12
为a int
,因此比较是有符号整数的比较.
int x = -3;
printf("%d\n", x < 12); // prints 1 because it's true that -3 < 12
Run Code Online (Sandbox Code Playgroud)
使用U
后缀,比较成为无符号整数的比较."通常的算术转换"意味着-3被转换为大的unsigned int:
printf("%d\n", x < 12U); // prints 0 because (unsigned int)-3 is large
Run Code Online (Sandbox Code Playgroud)
实际上,常量的类型甚至可能改变算术计算的结果,这也是因为"通常的算术转换"的工作方式.
请注意,对于十进制常量,C99建议的类型列表不包含unsigned long long
.在C90中,列表以当时最大的标准化无符号整数类型结束(即unsigned long
).结果是通过将标准类型添加long long
到C99来改变某些程序的含义:unsigned long
在C90 中键入的相同常量现在可以作为签名输入long long
.我相信这就是为什么在C99中,决定不在unsigned long long
十进制常量的类型列表中.见这个和这个为例的博客文章.
小智 10
因为数字文字通常是int类型.UL/L告诉编译器它们不是int类型,例如假设32位int和64位long
long i = 0xffff;
long j = 0xffffUL;
Run Code Online (Sandbox Code Playgroud)
这里右边的值必须转换为有符号长(32位 - > 64位)
问题是为什么我们应该在长常量中使用L/UL,即使在声明它很长之后也是如此.
因为它不是"之后"; 它是"之前".
首先你有文字,然后它被转换为你试图挤压它的变量的类型.