【发布时间】:2014-04-25 07:50:36
【问题描述】:
int main()
{
unsigned int i = 12;
printf("%lu", i); // This yields a compiler warning
}
在 32 位平台上,使用 printf 和使用 %lu 的 int 会导致垃圾吗?
【问题讨论】:
int main()
{
unsigned int i = 12;
printf("%lu", i); // This yields a compiler warning
}
在 32 位平台上,使用 printf 和使用 %lu 的 int 会导致垃圾吗?
【问题讨论】:
仅声明“32 位平台”并不意味着 int 和 long 以及它们的 unsigned 对应物都具有 32 位。
所以是的,如果 unsingned long(%lu 的用途)比 unsigned int 长,确实会发生这种情况。
但即使长度相等,类型也不兼容,所以形式上它是未定义的行为。
【讨论】:
LP64 (en.cppreference.com/w/cpp/language/types) 中,long 是 64 位,int 是 32 位。
int 和 long 都是 32 位。
%lu 与unsigned long 类型匹配。 unsigned long 和 unsigned int 类型即使具有相同的宽度也不相同,即使它们传递一个给另一个也是未定义的行为。
如果需要的类型和给定的类型不兼容,你
有未定义的行为。编译器完全合法
传递 vararg 时将类型信息与值一起传递,并且
在va_arg 中利用它(虽然我不知道有哪个,
可能是历史原因)。
至于您的具体情况的实际效果,"%lu"
期望一个无符号长。唯一的其他类型是
兼容是长的,然后只有当实际值
long 是非负的。传递int 是未定义的
行为,尽管它可能有效。 (在大多数 32 位平台上,
int 和 long 具有相同的大小和表示形式。)
【讨论】:
int 和 long 具有不同表示的平台上,您更有可能看到明显奇怪的东西。
int 和long 都是4 个字节,行为也未定义。如上所述,实现可以将类型信息与值一起传递,并在va_arg 中使用它来确保传递了正确的类型。
老实说,我不明白为什么要使用 %lu 代替 %u,因为您使用的是 int。
%lu 应该(在其非常基本的解释中)用于 unsigned long。
如果您的编译器对 int 和 long 使用不同的存储大小(当然在 99% 的情况下会这样做),它很可能会打印垃圾。
例如,根据 C 标准,就存储大小而言,unsigned int 是“至少 16 位大小”。而 unsigned long 是“至少 32 位大小”。
现在,让我们以 16 位 int 和 32 位 long 为例,并考虑一个非典型示例,在您运行程序时内存全部归零。
你的值 12 在内存中表示为:
00000000 00001100
如果你用 %u 打印会得到 12:
如果指示 printf 打印为 %lu 会导致 printf 占用的内存为:
00000000 00001100 00000000 00000000
对应786432的long值
编辑: 将变量的值传递给 printf 函数(而不是变量的指针(和大小))使代码无论如何都可以工作。我之前的“解释”主要是解释为什么提出警告以及为什么它“通常”是一种错误的方法。
【讨论】:
printf 的问题更复杂,但在最常见的平台(基于英特尔)上,整数是小端的,所以按字节计算,他的 12 将是 0C 00(在16 位)或 0C 00 00 00(32 位)。