为什么我们不能用C语言中的“%d”代替带有指针的“%u”?

时间:2013-05-24 00:37:15

标签: c pointers

%u用于无符号数字 如果我使用%d代替%u来显示变量的地址,我会得到相同的结果 我们仅将%u用于道德规范,或者它也会产生任何真正的差异 看看:

int i=5;
printf("Address of i: %d", &i);

与:

相同
printf("Again, address: %u" ,&i);

[编辑]将会赞赏它产生不同输出的例子。

5 个答案:

答案 0 :(得分:7)

你可以在不经过多次往返的情况下过马路,也可能不会受到汽车撞击。这并不意味着这是一个好主意。

答案 1 :(得分:3)

  • %d将为具有最高位设置(高地址)的地址显示负值
  • %u将始终显示位
  • 的正解释
  • %p是最好的,因为它明确保留用于打印地址。

考虑这一点,假设地址为0xffffffff

#include <stdio.h>

int main () {
    void* val = 0xffffffff;

    printf("d = %d\n", val);
    printf("u = %u\n", val);
    printf("p = %p\n", val);

    return 0;
}

并且,它是输出:

d = -1
u = 4294967295
p = 0xffffffff

答案 2 :(得分:2)

实际上,即使"%u"也是错的;对于指针,您必须使用"%p"


仍然,%d - 取而代之的是%u,因为在您的架构上签名和无符号数字具有相同的表示,因为我们正在查看正数。因此,如果您将指针传递给%dprintf将尝试将参数解释为有符号整数,只要高位,您将得到%u的相同结果未设置指针(通常是用户模式指针的标准);否则,您将获得%d的负数和带%u的正数(假设您的机器使用2的补码算术)。

有趣的是,最大的错误不是匹配签名,而是使用整数指定符(%d%u)而不是指针指定符(%p);实际上,大多数64位架构int是32位,但void *是64位,因此使用%u代替%p只会打印一半的地址(小端架构的下半部分,如x86_64)。

注意:所有这些解释都来自C语言的“典型实现”;就标准而言,如果您不匹配格式指定符的类型和实际数据,则会进入“未定义的行为”(=从崩溃到粉红色独角兽飞出打印机的任何内容)。

答案 3 :(得分:2)

在C中打印指针时,您应该使用%p,而不是%u%d%u%d旨在显示整数值。当您使用这些标志打印出指针时,您隐式地将指针转换为整数,并且有很多架构会导致很多麻烦(特别是在64位架构中)。

%d%u之间的区别与您提到的不同,%u将值视为无符号,%d视为已签名。如果最高位为1,结果将不同。使用-1时,您可以轻松看到这一点。

printf("%d, %u\n", -1, -1);

输出:

-1,4294967295

答案 4 :(得分:0)

存在不寻常的CPU架构,其中指针具有与无符号数字不同的表示或大小。

一个常见示例是以分段模式写入的32位x86代码,其中地址由具有32位段偏移的16位段号组成。 (免责声明:我看了这几年已经好几年了,所以我可能忘记了细节。)

另一种情况是64位机器设置为使用64位指针和32位整数。