我在C语言中这样打印指针是否正确?为何出现输出异常与编译警告
问题说明与修正方案
对核心疑问的直接回应
- 你当前用
%i打印指针的方式完全错误,不符合C语言的类型匹配规则 - 你看到的一长串负数是类型不匹配、截断指针值产生的错误输出,属于异常结果,不是真实的内存地址
编译警告的产生原因
%i是专门为打印有符号int类型整数设计的格式化占位符,只接受int类型的参数- 你的代码里传入的参数全是各级指针(
int*、int**、int***),类型和%i要求的int不匹配,编译器自然会抛出大量格式不匹配的警告 - 这种不匹配的参数传递属于C语言定义的未定义行为,运行结果没有标准保障
负地址的生成逻辑
现在主流运行环境是64位系统:
- 指针的存储长度是8字节,常规int类型只有4字节
- 当你把8字节的指针值传给期待4字节int的
%i时,高位的4字节会被直接截断 - 截断后的32位值如果最高位(有符号数的符号位)为1,就会被解读成负数输出,所以你看到的大负数本质是被截断的错误值
- 虽然数值是错的,但逻辑对应关系和真实地址是一致的:比如本来指向同一个变量的
&a、p、*q、**r,截断后的值完全相同,和你输出里的重复数值是对应的
正确的指针打印方式
C语言为指针打印提供了专属的格式化占位符%p:
- 打印任意级别的指针值时,使用
%p作为格式符,并将指针强转为void*类型传入,就能完全匹配C标准要求,彻底消除编译警告 - 使用
%p输出的地址会以标准十六进制形式展示,不会出现截断导致的负数 - 注意:解引用指针得到的结果如果是int类型(比如
*p、**q、***r),本身就是合法的int值,继续用%i打印是正确的,这也是你输出里几个10是正常值的原因
修正后的可正常编译运行的测试代码
#include <stdio.h> int main(){ int a = 10; int *p = &a; int **q = &p; int ***r = &q; printf("%i\n", a); printf("%p\n", (void*)&a); printf("%p\n", (void*)p); printf("%p\n", (void*)&p); printf("%i\n", *p); printf("%p\n", (void*)q); printf("%p\n", (void*)&q); printf("%p\n", (void*)*q); printf("%i\n", *(*q)); printf("%p\n", (void*)r); printf("%p\n", (void*)&r); printf("%p\n", (void*)*r); printf("%p\n", (void*)*(*r)); printf("%i\n", *(*(*r))); return 0; }
内容的提问来源于stack exchange,提问作者user15380805
相关产品推荐
相关产品推荐

