为长值明确声明L或UL的原因是什么?

从一个例子

unsigned long x = 12345678UL 

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

当不使用后缀LUL ,编译器使用可以包含列表中常量的第一种类型(请参阅C99标准中的详细信息,第6.4.4节:5。对于十进制常量,列表为intlong intlong 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 。 在每个例子中,这都会产生溢出的风险。 使用后缀意味着计算将以更大的类型完成,其具有足够的结果范围。

正如Orbit中的Lightness Races所说,litteral的后缀出现任务之前 。 在上面的两个例子中,简单地将xlong ,将yunsigned 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被转换为大的unsigned 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 。 有关示例,请参阅此博客文章。

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

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

这里右边的值必须转换为有符号长(32位 – > 64位)

  1. “0xffff”,一个int,将使用符号扩展转换为long,从而产生负值(0xffffffff)
  2. “0xffffUL”(无符号长整数)将转换为long,从而产生正值(0x0000ffff)

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

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

首先你有文字, 然后它被转换为你试图挤压它的变量的类型。

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

u一个原因是允许以十进制forms大于LLONG_MAX整数常量

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