为长值显式声明 L 或 UL 的原因是什么 [英] what is the reason for explicitly declaring L or UL for long values

查看:11
本文介绍了为长值显式声明 L 或 UL 的原因是什么的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

举个例子

无符号长 x = 12345678UL

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

解决方案

当不使用后缀LUL时,编译器使用第一个可以包含的类型列表中的常量(参见 C99 标准第 6.4.4:5 节中的详细信息.对于十进制常量,列表为 intlong intlong长整数).

因此,大多数时候,没有必要使用后缀.它不会改变程序的含义.对于大多数体系结构,它不会改变 x 的示例初始化的含义,尽管如果您选择了一个不能表示为 long long 的数字,它会改变.有关后缀的 U 部分是必需的示例,另请参见 codebauer 的答案.

<小时>

在某些情况下,程序员可能想要显式设置常量的类型.一个例子是使用可变参数函数时:

printf("%lld", 1LL);//正确,因为 1LL 的类型为 long longprintf("%lld", 1);//未定义的行为,因为 1 的类型为 int

<小时>

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

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

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

正如 Lightness Races in Orbit 所说,litteral 的后缀出现在 分配之前.在上面的两个例子中,仅仅将 x 声明为 long 并将 y 声明为 unsigned long long 并不足以防止分配给它们的表达式的计算溢出.

<小时>

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

int x = -3;printf("%d
", x <12);//打印 1 因为确实 -3 <12

使用 U 后缀,比较变成无符号整数的比较.通常的算术转换"意味着 -3 被转换为一个大的无符号整数:

printf("%d
", x <12U);//打印 0 因为 (unsigned int)-3 很大

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

<小时>

请注意,对于十进制常量,C99 建议的类型列表不包含 unsigned long long.在 C90 中,该列表以当时最大的标准化无符号整数类型(即 unsigned long)结束.结果是通过将标准类型 long long 添加到 C99 来改变某些程序的含义:在 C90 中键入为 unsigned long 的相同常量现在可以键入作为签名的 long long 代替.我相信这就是为什么在 C99 中决定在十进制常量的类型列表中不包含 unsigned long long 的原因.请参阅 thisthis 博客文章为例.p>

From an Example

unsigned long x = 12345678UL

We have always learnt that the compiler needs to see only "long" in the above example to set 4 bytes (in 32 bit) of memory. The question is why is should we use L/UL in long constants even after declaring it to be a long.

解决方案

When a suffix L or UL is not used, the compiler uses the first type that can contain the constant from a list (see details in C99 standard, clause 6.4.4:5. For a decimal constant, the list is int, long int, long long int).

As a consequence, most of the times, it is not necessary to use the suffix. It does not change the meaning of the program. It does not change the meaning of your example initialization of x for most architectures, although it would if you had chosen a number that could not be represented as a long long. See also codebauer's answer for an example where the U part of the suffix is necessary.


There are a couple of circumstances when the programmer may want to set the type of the constant explicitly. One example is when using a variadic function:

printf("%lld", 1LL); // correct, because 1LL has type long long
printf("%lld", 1);   // undefined behavior, because 1 has type int


A common reason to use a suffix is ensuring that the result of a computation doesn't overflow. Two examples are:

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

In both examples, without suffixes, the constants would have type int and the computation would be made as int. In each example this incurs a risk of overflow. Using the suffixes means that the computation will be done in a larger type instead, which has sufficient range for the result.

As Lightness Races in Orbit puts it, the litteral's suffix comes before the assignment. In the two examples above, simply declaring x as long and y as unsigned long long is not enough to prevent the overflow in the computation of the expressions assigned to them.


Another example is the comparison x < 12U where variable x has type int. Without the U suffix, the compiler types the constant 12 as an int, and the comparison is therefore a comparison of signed ints.

int x = -3;
printf("%d
", x < 12); // prints 1 because it's true that -3 < 12

With the U suffix, the comparison becomes a comparison of unsigned ints. "Usual arithmetic conversions" mean that -3 is converted to a large unsigned int:

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

In fact, the type of a constant may even change the result of an arithmetic computation, again because of the way "usual arithmetic conversions" work.


Note that, for decimal constants, the list of types suggested by C99 does not contain unsigned long long. In C90, the list ended with the largest standardized unsigned integer type at the time (which was unsigned long). A consequence was that the meaning of some programs was changed by adding the standard type long long to C99: the same constant that was typed as unsigned long in C90 could now be typed as a signed long long instead. I believe this is the reason why in C99, it was decided not to have unsigned long long in the list of types for decimal constants. See this and this blog posts for an example.

这篇关于为长值显式声明 L 或 UL 的原因是什么的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆