12

在 c 中,我试图打印出变量的地址和某些函数的地址。我得到一个是负值,另一个是正值。我的问题是:为什么 C 不代表所有负值或所有正值?

这是我的代码:

int foo() { 
     return 0;
}

int main() {

    int a;
    printf("%d\n",&a);

    printf("%d\n",foo);

    return 0;
}

这是结果:

-1075908992 134513684
4

10 回答 10

36

内存地址不应以这种方式解释为有符号整数。数字的符号取决于最高位集(假设二进制补码表示,目前绝大多数系统都使用这种表示),因此 32 位系统上 0x80000000 以上的内存地址将为负数,而内存低于 0x80000000 的地址将为正数。这没有真正的意义。

您应该使用%p修饰符打印内存地址;或者,有些人%08x用于打印内存地址(或%016llx在 64 位系统上)。这将始终打印为十六进制的无符号整数,这比有符号十进制整数有用得多。

int a;
printf("%p\n", &a);
于 2009-11-06T18:32:36.730 回答
7

要尽可能符合标准,请将格式字符串中的 "%p" 传递给printf()并将参数转换为void*.

printf("%p\n", (void*)&a);
printf("%p\n", (void*)foo);

引用标准草案 (n1401.pdf)

    7.20.6.1 fprintf 函数

8 转换说明符及其含义是:

p 参数应该是一个指向 void 的指针。指针的值
        转换为打印字符序列,在
        实现定义的方式。
于 2009-11-06T18:43:04.303 回答
6

您应该传递指针格式化程序:

printf("%p\n",foo);
于 2009-11-06T18:32:27.730 回答
4

您正在以十进制打印。您可能希望以十六进制打印内存位置(使用“%p”)(大多数内存地址按惯例以十六进制显示)。

于 2009-11-06T18:32:53.437 回答
3

两者都没有,指针没有符号,但是当转换为有符号整数时,它可能是正数或负数。

顺便说一句,将指针传递给printf旨在打印整数的格式变量会导致未定义的行为。您应该始终显式转换为正确的类型以获得未指定或实现定义的行为(取决于转换)。

于 2009-11-06T18:32:44.480 回答
3

指针不是有符号整数,更像是无符号整数。但是,您将它们打印出来,就好像它们是有符号整数一样。在 32 位系统上,有几件事可能是 32 位长: intunsigned intfloat和指针。您通常无法仅通过查看它们来判断它们,但它们都意味着不同的东西。(作为一个实验,你可以传入各种整数并像浮点数一样打印它们,反之亦然:这通常是不好的做法,但它可以告诉你不同的数据类型确实意味着不同的东西。)

采用可变数量参数的函数(“可变”函数)以一种复杂的方式执行此操作。特别是,它们不检查参数类型。你可以传递任何你喜欢的参数printf()和类似的函数,但是让它们与格式说明符一致是你的问题。这意味着该函数无法正确获取类型(就像您将 a 传递float给类似 的函数一样int foo(int))。

传递错误类型的参数会导致未定义的行为,如果传递大小错误的参数,则尤其可能导致问题。在大多数 64 位系统上,指针是 64 位,ints 是 32 位。

因此,您需要在格式字符串中使用正确的东西。 printf("%p", &a);将打印出a作为指针的地址,这就是你想要的。该标准需要类似的东西printf("%p", (void *)&a);,但作为一个实际问题,在您可能遇到的任何计算机上都是不必要的。

于 2009-11-06T19:07:10.077 回答
1

你也可以使用printf("%p", &a)%p是指针格式说明符,以实现定义的方式输出指针的值。实际上,它与 %x 几乎相同,但会处理指针大于 int 的情况。

于 2009-11-06T18:34:42.997 回答
0

使用以下代码:

printf("%u",&a);
于 2009-11-06T18:32:56.287 回答
0

printf 不是一些神奇的解释工具。如果你给它“%d”,它所做的就是向你展示位于该变量中的位模式看起来像一个整数。

至于为什么有些指针是负数而有些是正数,这意味着有些指针设置了高位,有些则没有。为对象分配的地址实际上只是您的操作系统的业务(通常有一些硬件帮助)。编程语言在其中没有真正的发言权。

如果我是你,我不会那样打印地址。如果您真的觉得有必要查看它们,请使用“%x”而不是“%d”。这将以十六进制打印它们,这样可以更容易地确定哪些位在,哪些位不在。一般来说,您要关心的地址是它们是否为 0,以及它们是否与其他地址的值匹配。

于 2009-11-06T18:56:31.910 回答
0

除了使用之外%p,您还可以uintptr_t强制转换为以确保获得一个无符号整数。

使用PRIuPTR(或PRIXPTR十六进制)形式<inttypes.h>来获得正确的格式说明符:

printf("%" PRIuPTR "\n", (uintptr_t)(void *)&foo);
于 2009-11-06T20:14:20.223 回答