Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/apache/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 打印指针或地址的格式说明符是否正确?_C_Pointers_Format_Memory Address - Fatal编程技术网

C 打印指针或地址的格式说明符是否正确?

C 打印指针或地址的格式说明符是否正确?,c,pointers,format,memory-address,C,Pointers,Format,Memory Address,我应该使用哪个格式说明符来打印变量的地址?我对下面这批货感到困惑 %u-无符号整数 %十六进制值 %p-void指针 哪种格式是打印地址的最佳格式?p是打印指针的转换说明符。用这个 int a = 42; printf("%p\n", (void *) &a); 请记住,省略强制转换是未定义的行为,使用p转换说明符的打印是以实现定义的方式完成的。使用%p作为“指针”,不要使用其他任何东西*。标准并不能保证您可以像对待任何特定类型的整数一样对待指针,因此您实际上会得到整数格式的未定义行

我应该使用哪个格式说明符来打印变量的地址?我对下面这批货感到困惑

%u-无符号整数

%十六进制值

%p-void指针


哪种格式是打印地址的最佳格式?

p
是打印指针的转换说明符。用这个

int a = 42;

printf("%p\n", (void *) &a);
请记住,省略强制转换是未定义的行为,使用
p
转换说明符的打印是以实现定义的方式完成的。

使用
%p
作为“指针”,不要使用其他任何东西*。标准并不能保证您可以像对待任何特定类型的整数一样对待指针,因此您实际上会得到整数格式的未定义行为。(例如,
%u
需要一个
无符号整数
,但是如果
void*
的大小或对齐要求与
无符号整数
不同呢?)

*)[参见Jonathan的精彩答案!]除了
%p
,您还可以使用C99中添加的
中特定于指针的宏

在C中,所有对象指针都可以隐式转换为
void*
,但为了将指针作为变量参数传递,必须显式转换它(因为任意对象指针只能转换,但与void指针不同):


最简单的答案是标准的
%p
表示法,假设您不介意不同平台之间格式的变化

C99标准(ISO/IEC 9899:1999)在§7.19.6.1¨8中规定:

p
参数应是指向
void
的指针。指针的值为 在定义的实现中转换为打印字符序列 态度

(在C11-ISO/IEC 9899:2011中,信息见§7.21.6.1¨8。)

在一些平台上,这将包括一个前导的
0x
,而在其他平台上则不会,字母可以是小写或大写,C标准甚至没有定义它应该是十六进制输出,尽管我知道没有实现它

是否应该使用
(void*)
强制转换显式转换指针,这是一个有争议的问题。它是明确的,这通常是好的(我就是这么做的),标准说“参数应该是指向
void
”的指针。在大多数机器上,您可以忽略显式强制转换。但是,如果给定内存位置的
char*
地址的位表示不同于同一内存位置的“任何其他指针”地址,则这在机器上很重要。这将是一个字寻址的机器,而不是字节寻址的机器。这类机器现在并不常见(可能不可用),但我大学毕业后使用的第一台机器就是这样的(ICL Perq)

如果您对
%p
的实现定义的行为不满意,请改用C99
uintpttr\t

printf("0x%" PRIXPTR "\n", (uintptr_t)your_pointer);
这允许您微调表示以适合自己。我选择了大写的十六进制数字,这样数字的高度就一致了,并且
0xA1B2CDEF
开头的特征倾斜就出现了,而不像
0xA1B2CDEF
那样沿着数字上下倾斜。不过,你的选择范围很广。GCC明确建议使用
(uintpttr\t)
cast,因为它可以在编译时读取格式字符串。我认为这是正确的要求演员,虽然我相信有人会忽视警告,并逃脱了大部分时间


Kerrek在评论中问道:


我对标准促销和可变参数有点困惑。是否所有指针都将标准升级为void*?否则,如果
int*
是两个字节,而
void*
是4个字节,那么从参数中读取四个字节显然是错误的,不是吗

我误以为C标准规定所有对象指针必须是相同的大小,所以
void*
int*
不能是不同的大小。然而,我认为C99标准的相关部分并没有那么强调(尽管我不知道有哪个实现我所建议的是正确的,而实际上是错误的):

§6.2.5类型

26指向void的指针应与指向字符类型的指针具有相同的表示和对齐要求。39)同样,指向兼容类型的合格或不合格版本的指针应具有相同的表示和对齐要求。指向结构类型的所有指针应具有彼此相同的表示和对齐要求。所有指向联合类型的指针应具有彼此相同的表示和对齐要求。指向其他类型的指针不需要具有相同的表示或对齐要求

39)相同的表示和对齐要求意味着作为函数参数、函数返回值和联合成员的互换性

(C11在§6.2.5、28和脚注48中的表述完全相同。)

因此,指向结构的所有指针必须彼此大小相同,并且必须共享相同的对齐要求,即使指针指向的结构可能具有不同的对齐要求。工会也是如此。字符指针和空指针必须具有相同的大小和对齐要求。指向
int
(意思是
unsigned int
signed int
)变体的指针必须具有彼此相同的大小和对齐要求;其他类型的情况也类似。但是C标准没有正式地说
sizeof(int*)==sizeof(void*)
。哦,好吧,这有助于让你检查你的假设

C站
printf("0x%" PRIXPTR "\n", (uintptr_t)your_pointer);