C 为什么%u%d不能在UNIX/LINUX上打印地址

C 为什么%u%d不能在UNIX/LINUX上打印地址,c,linux,unix,pointers,C,Linux,Unix,Pointers,我知道%d代表int,%u代表未签名int,%p代表地址。 但我的问题是,我们可以在Windows计算机上使用%u、%d打印地址,但在Linux上不能这样做 例如: #include<stdio.h> int main() { int x=15; int *p; p=&x; printf("%d \n",x); printf("%d \n",&x); printf("%u \n",&x); print

我知道%d代表int,%u代表未签名int,%p代表地址。 但我的问题是,我们可以在Windows计算机上使用%u、%d打印地址,但在Linux上不能这样做

例如:

#include<stdio.h>

int main() {
    int x=15;
    int *p;
    p=&x;

    printf("%d \n",x);
    printf("%d \n",&x);
    printf("%u \n",&x);
    printf("%p \n",p);
    printf("%x \n",p);
    printf("%u \n",&p);

return 0;   
}
可以看出,十六进制值(23fe1c)使用%d和%u更改为十进制

但同样的代码在Unix/Linux上给出了错误

错误:

format (%d) expects arguments of type 'int', but argument 2 has type 'int*'

GCC能够对可变函数执行类型检查,特别是使用。这将强制检查作为可变参数传递的类型是否与提供的格式字符串完全匹配。

GCC抱怨,因为printf格式字符串中使用的数据类型与传递的参数不兼容。打印指针的便携式标准方法是使用%p说明符。但是,您可以找到其他地方,在那里人们可能会出于同样的目的使用%x。正如其他人所说,使用%u和%d与指针数据类型不兼容。它们可能在某些编译器上工作,如Windows情况下,但其他更严格的编译器(如本例中的GCC)可能会抱怨传递的数据类型,因为intint*不同。为了使用%p符号,必须将指针强制转换为void,如C99标准:

p参数应是指向void的指针。指针的值以实现定义的方式转换为一系列打印字符

也就是说,定义了%p实现,因此输出可以从一个实现更改为另一个实现。一般来说,使用%d或%u打印指针都不是一个好主意。根据实现的不同,指针可以是简单整数或长整数。因此,如果在地址存储在长整数变量中的计算机上尝试使用%d或%u打印指针,则可能会出现未定义的行为


如果要控制输出,另一个选项是使用
\include
提供的
uintpttr\t

将不匹配的数据提供给
printf
会导致未定义的行为。Windows上的编译器意外接受了它,但Linux上的编译器没有接受。请注意,
%p
用于打印
void*
,因此在将指针传递到
printf
之前,应先转换指针,即
printf(“%p\n”,(void*)p)
为了清楚起见,不能使用
%d
打印指针值,因为指针不是整数。整数不是指针。仅仅因为使用
%d
打印指针在某些平台上有效,并不意味着它在任何地方都有效。但将指针视为一个整数是错误的——无论在何处。当您开始进行64位编程时,您将了解到这一点。根据实现的不同,指针可以是简单的整数或长的整数。它甚至可以是两个整数。您是指例如64位机器中的编译器使用4字节整数的情况吗?不,我指的是分段地址,如:
0xabcd:0x1234
(进一步阅读:)实际上,
%p
在(a)64位地址变得普遍,以及(b)更晚的时候,gcc添加了一个警告,指出这是一个问题。分段地址最好发出警告,但逾期20年表明它们不是gcc警告的因素。
format (%d) expects arguments of type 'int', but argument 2 has type 'int*'