内存地址c中的正值或负值?
在c中,我试图打印出变量的地址和某些function的地址。 我得到一个是负值,另一个是正值。 我的问题是:为什么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
打印内存地址(或64位系统上的%016llx
)。 这将始终打印为hex的无符号整数,这比带符号的十进制整数更有用。
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);
你用十进制打印出来。 您可能希望以hex打印出内存位置(使用“%p”)(大多数内存地址按照惯例以hex显示)。
也没有,指针没有符号,但是当转换为有符号整数时,它可能是正数或负数。
顺便提一下,将指针传递给printf
并使用设计用于打印整数的格式变量会导致未定义的行为。 您应该始终显式地转换为正确的类型以获取未指定的或实现定义的行为(取决于强制转换)。
指针不是有符号整数,更像是无符号整数。 但是,您将它们打印出来就好像它们是有符号整数一样。 在32位系统上,有几件事可能是32位长: int
, unsigned int
, float
和pointers。 你不能一般地通过观察它们来判断这些是什么,但它们都意味着不同的东西。 (作为一个实验,你可以传递各种整数并像浮动一样打印它们,反之亦然:这通常是不好的做法,但它可以告诉你不同的数据类型确实意味着不同的东西。)
采用可变数量参数的函数(“可变参数”函数)以复杂的方式执行。 特别是,它们不检查参数类型。 您可以将任何您喜欢的参数传递给printf()
和类似的函数,但让它们同意格式说明符是您的问题。 这意味着函数无法正确获取类型(就像将float
传递给类似int foo(int)
的函数一样)。
传递错误类型的参数会导致未定义的行为,如果传递的参数大小错误,则特别容易导致问题。 在大多数64位系统上,指针是64位, int
是32。
因此,您需要在格式字符串中使用正确的东西。 printf("%p", &a);
将打印出a的地址作为指针,这就是你想要的。 该标准需要类似printf("%p", (void *)&a);
,但作为一个实际问题,在你可能遇到的任何计算机上都是不必要的。
您也可以使用printf("%p", &a)
。 %p
是指针格式说明符,以实现定义的方式输出指针的值。 实际上,它与%x几乎相同,但会处理指针大于int的情况。
printf不是一些神奇的解释工具。 如果你给它“%d”它正在做的就是向你展示那个变量中的位模式看起来像一个整数。
至于为什么有些指针是负数而有些是正数,所有这些意味着有些指针设置了高位,有些指针则没有。 给对象的地址实际上只是操作系统的业务(通常有一些硬件帮助)。 编程语言没有真正的发言权。
如果我是你,我不会那样打印出地址。 如果您确实需要查看它们,请使用“%x”而不是“%d”。 这将以hex打印它们,这使得更容易找出哪些位是打开的,哪些不是。 通常情况下,您要关注的是地址是否为0,如果它们与其他地址的值相匹配。
除了使用%p
之外,您还可以uintptr_t
为uintptr_t
以确保获得未分配的整数。
使用PRIuPTR
(或PRIXPTR
)格式
来获取正确的格式说明符:
printf("%" PRIuPTR "\n", (uintptr_t)(void *)&foo);
使用以下代码:
printf("%u",&a);