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

Sha*_*ash 30 c constants

从一个例子

unsigned long x = 12345678UL
Run Code Online (Sandbox Code Playgroud)

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

Pas*_*uoq 61

当一个后缀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
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的后缀出现任务之前.在上面的两个例子中,简单地声明xas longyas 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十进制常量的类型列表中.见这个这个为例的博客文章.

  • 即使编译器可以选择数字文字的大小,它也不会自动确定它是否已签名.例如,在具有64位"long"的系统上,`18446744073709551615`被视为`-1L`.你必须明确使用`UL`. (3认同)
  • 小补充:在某些情况下,它还可以提高可读性并提示建议用法。例如,您可能有类似`#define MY_DEFINE 123456789UL` 的内容,而您稍后在代码中使用了`MY_DEFINE`。自然地,它没有与之关联的类型,因此添加“UL”在这里可能没什么帮助。 (2认同)

小智 10

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

long i = 0xffff;
long j = 0xffffUL;
Run Code Online (Sandbox Code Playgroud)

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

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

  • @PascalCuoq 不同意这是一个_nice_示例。在 C99 中,“0xffff”是一个值为 65,535 的“int”。将其分配给“i”不是问题。`0xffffUL` 是一个 `unsigned long`,值为 65,535。将其分配给“j”也不是问题。如果这个例子是“long i = 0xffffffff;”,“0xffffffff”是一个“无符号”,值为 4,294,967,295,将其分配给 64-“long”不是问题。另外,“long j = 0xffffffffUL;”也不是问题。这个答案的#1“使用符号扩展转换为 long”在这里并不正确。 (2认同)

Lig*_*ica 6

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

因为它不是"之后"; 它是"之前".

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

  • 我希望我们可以写“LUL”而不是“ULL”:) (3认同)