在 c 中,我试图打印出变量的地址和某些函数的地址。我得到一个是负值,另一个是正值。我的问题是:为什么 C 不代表所有负值或所有正值?
这是我的代码:
int foo() {
return 0;
}
int main() {
int a;
printf("%d\n",&a);
printf("%d\n",foo);
return 0;
}
这是结果:
-1075908992 134513684
在 c 中,我试图打印出变量的地址和某些函数的地址。我得到一个是负值,另一个是正值。我的问题是:为什么 C 不代表所有负值或所有正值?
这是我的代码:
int foo() {
return 0;
}
int main() {
int a;
printf("%d\n",&a);
printf("%d\n",foo);
return 0;
}
这是结果:
-1075908992 134513684
内存地址不应以这种方式解释为有符号整数。数字的符号取决于最高位集(假设二进制补码表示,目前绝大多数系统都使用这种表示),因此 32 位系统上 0x80000000 以上的内存地址将为负数,而内存低于 0x80000000 的地址将为正数。这没有真正的意义。
您应该使用%p
修饰符打印内存地址;或者,有些人%08x
用于打印内存地址(或%016llx
在 64 位系统上)。这将始终打印为十六进制的无符号整数,这比有符号十进制整数有用得多。
int a;
printf("%p\n", &a);
要尽可能符合标准,请将格式字符串中的 "%p" 传递给printf()
并将参数转换为void*
.
printf("%p\n", (void*)&a);
printf("%p\n", (void*)foo);
引用标准草案 (n1401.pdf)
7.20.6.1 fprintf 函数 8 转换说明符及其含义是: p 参数应该是一个指向 void 的指针。指针的值 转换为打印字符序列,在 实现定义的方式。
您应该传递指针格式化程序:
printf("%p\n",foo);
您正在以十进制打印。您可能希望以十六进制打印内存位置(使用“%p”)(大多数内存地址按惯例以十六进制显示)。
两者都没有,指针没有符号,但是当转换为有符号整数时,它可能是正数或负数。
顺便说一句,将指针传递给printf
旨在打印整数的格式变量会导致未定义的行为。您应该始终显式转换为正确的类型以获得未指定或实现定义的行为(取决于转换)。
指针不是有符号整数,更像是无符号整数。但是,您将它们打印出来,就好像它们是有符号整数一样。在 32 位系统上,有几件事可能是 32 位长: int
、unsigned int
、float
和指针。您通常无法仅通过查看它们来判断它们,但它们都意味着不同的东西。(作为一个实验,你可以传入各种整数并像浮点数一样打印它们,反之亦然:这通常是不好的做法,但它可以告诉你不同的数据类型确实意味着不同的东西。)
采用可变数量参数的函数(“可变”函数)以一种复杂的方式执行此操作。特别是,它们不检查参数类型。你可以传递任何你喜欢的参数printf()
和类似的函数,但是让它们与格式说明符一致是你的问题。这意味着该函数无法正确获取类型(就像您将 a 传递float
给类似 的函数一样int foo(int)
)。
传递错误类型的参数会导致未定义的行为,如果传递大小错误的参数,则尤其可能导致问题。在大多数 64 位系统上,指针是 64 位,int
s 是 32 位。
因此,您需要在格式字符串中使用正确的东西。 printf("%p", &a);
将打印出a
作为指针的地址,这就是你想要的。该标准需要类似的东西printf("%p", (void *)&a);
,但作为一个实际问题,在您可能遇到的任何计算机上都是不必要的。
你也可以使用printf("%p", &a)
。%p
是指针格式说明符,以实现定义的方式输出指针的值。实际上,它与 %x 几乎相同,但会处理指针大于 int 的情况。
使用以下代码:
printf("%u",&a);
printf 不是一些神奇的解释工具。如果你给它“%d”,它所做的就是向你展示位于该变量中的位模式看起来像一个整数。
至于为什么有些指针是负数而有些是正数,这意味着有些指针设置了高位,有些则没有。为对象分配的地址实际上只是您的操作系统的业务(通常有一些硬件帮助)。编程语言在其中没有真正的发言权。
如果我是你,我不会那样打印地址。如果您真的觉得有必要查看它们,请使用“%x”而不是“%d”。这将以十六进制打印它们,这样可以更容易地确定哪些位在,哪些位不在。一般来说,您要关心的地址是它们是否为 0,以及它们是否与其他地址的值匹配。
除了使用之外%p
,您还可以uintptr_t
强制转换为以确保获得一个无符号整数。
使用PRIuPTR
(或PRIXPTR
十六进制)形式<inttypes.h>
来获得正确的格式说明符:
printf("%" PRIuPTR "\n", (uintptr_t)(void *)&foo);