显式声明长值的 L 或 UL 的原因是什么

问题描述 投票:0回答:5

来自示例

unsigned long x = 12345678UL

我们一直了解到,编译器只需要在上面的示例中看到“long”即可设置 4 个字节(32 位)内存。问题是为什么我们应该在 long 常量中使用 L/UL,即使在声明它是 long 之后也是如此。

c constants
5个回答
96
投票

当未使用后缀

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
进行。在每个示例中,这都会带来溢出的风险。使用后缀意味着计算将以更大的类型进行,这对于结果有足够的范围。

正如 Lightness Races in Orbit 所说,垃圾的后缀出现在任务之前。在上面的两个示例中,简单地将 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 被转换为一个大的无符号整数:

printf("%d\n", x < 12U); // prints 0 because (unsigned int)-3 is large

事实上,常量的类型甚至可能会改变算术计算的结果,这也是因为“通常的算术转换”的工作方式。


请注意,对于十进制常量,C99 建议的类型列表不包含

unsigned long long

。在 C90 中,列表以当时最大的标准化无符号整数类型结束(
unsigned long
)。结果是,通过将标准类型 
long long
 添加到 C99,某些程序的含义发生了变化:在 C90 中键入为 
unsigned long
 的相同常量现在可以键入为有符号 
long long
。我相信这就是为什么在 C99 中决定在十进制常量类型列表中不包含 
unsigned long long
 的原因。
有关示例,请参阅 
thisthis 博客文章。


21
投票
因为数字文字通常是 int 类型。 UL/L 告诉编译器它们不是 int 类型,例如假设 32 位 int 和 64 位 long

long i = 0xffff; long j = 0xffffUL;

这里右侧的值必须转换为有符号长整型(32位 -> 64位)

    “0xffff”,一个 int,将使用符号扩展转换为 long,导致负值 (0xffffffff)
  1. “0xffffUL”,一个无符号长整型,将被转换为一个长整型,得到一个正值(0x0000ffff)

14
投票
问题是为什么我们应该在 long 常量中使用 L/UL,即使在声明它是 long 之后也是如此。

因为它不是“之后”;是“之前”。

首先你有文字,

然后它被转换为你试图将其压缩到的变量的任何类型。

它们是两个对象。正如您所说,目标的类型由

unsigned long

 关键字指定。源的类型由此后缀指定,因为这是指定文字类型的唯一方法。


2
投票
与这篇文章相关的是为什么

u

u

的一个原因是允许
整数常量大于小数形式的LLONG_MAX

// Likely to generate a warning. unsigned long long limit63bit = 18446744073709551615; // 2^64 - 1 // OK unsigned long long limit63bit = 18446744073709551615u;
    

0
投票
这使得 C 编码很容易出错,对吧?对于新手来说,如果不付出“额外”的谨慎,很容易犯错误。如果 C 能够被设计成编译器能够自动检测数据值并根据代码上下文分配正确的类型,那就太好了。同意吗?

© www.soinside.com 2019 - 2024. All rights reserved.