49

从一个例子

unsigned long x = 12345678UL

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

4

4 回答 4

81

当后缀LUL不使用时,编译器使用第一种可以包含列表中的常量的类型(请参阅 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

使用后缀的一个常见原因是确保计算结果不会溢出。两个例子是:

long x = 10000L * 4096L;
unsigned long long y = 1ULL << 36;

在这两个示例中,如果没有后缀,常量将具有类型int,并且计算将按int. 在每个示例中,这都会导致溢出风险。使用后缀意味着计算将以更大的类型进行,它有足够的结果范围。

正如 Lightness Races in Orbit 所说,litteral 的后缀出现作业之前。在上面的两个示例中,仅声明xaslongyasunsigned long long不足以防止分配给它们的表达式的计算溢出。


另一个例子是x < 12U变量x具有类型的比较int。如果没有U后缀,编译器会将常量类型12int,因此比较是有符号整数的比较。

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)结束。结果是通过向 C99 添加标准类型改变了某些程序的含义long long:与在 C90 中键入的相同常量unsigned long现在可以键入为有符号long long。我相信这就是为什么在 C99 中决定不在unsigned long long十进制常量类型列表中的原因。有关示例,请参阅此博客文章。

于 2012-10-30T08:28:25.070 回答
17

因为数字文字是典型的 int 类型。UL/L 告诉编译器它们不是 int 类型,例如假设 32bit int 和 64bit long

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

此处右侧的值必须转换为有符号长整数(32 位 -> 64 位)

  1. “0xffff”,一个 int,将使用符号扩展转换为 long,导致负值 (0xffffffff)
  2. “0xffffUL”,一个无符号长整数,将被转换为一个长整数,产生一个正值(0x0000ffff)
于 2012-10-30T08:40:25.847 回答
10

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

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

首先,您拥有文字,然后将其转换为您尝试将其挤入的变量的任何类型。

它们是两个对象。unsigned long正如您所说,目标的类型由关键字指定。源的类型由此后缀指定,因为这是指定文字类型的唯一方法。

于 2012-10-30T12:47:44.823 回答
0

与这篇文章相关的是为什么u.

一个原因u是允许整数常量大于LLONG_MAX十进制形式。

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

// OK
unsigned long long limit63bit = 18446744073709551615u`;
于 2016-10-26T15:08:46.720 回答