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

时间:2012-10-30 08:10:21

标签: c constants

来自一个例子

unsigned long x = 12345678UL

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

4 个答案:

答案 0 :(得分:56)

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

随着Orbit中的Lightness Races的出现,litteral的后缀在之前分配。在上面的两个示例中,仅将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被转换为大的无符号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。 有关示例,请参阅thisthis博文。

答案 1 :(得分:8)

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

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

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

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

答案 2 :(得分:5)

  

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

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

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

答案 3 :(得分:0)

与此帖相关的是u

的原因

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

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

// OK
unsigned long long limit63bit = 18446744073709551615u`;