C++ 为什么';t%p是否显示指针的全宽?

C++ 为什么';t%p是否显示指针的全宽?,c++,c,memory,C++,C,Memory,如果我没有弄错的话,在64位机器上,指针相当于介于0和2^64-1之间的数字。因此得出以下结果: printf("%p", (void*) -1); → 0xffffffffffffffff printf("0x%lx", (uintptr_t) -1); → 0xffffffffffffffff 但是,当我从刚分配的对象打印指针时,结果显示的宽度并不相同: printf("%p", (void*) &myobject); → 0x70d940 我的所有对象(总是)在内

如果我没有弄错的话,在64位机器上,指针相当于介于
0
2^64-1
之间的数字。因此得出以下结果:

printf("%p",    (void*)     -1); → 0xffffffffffffffff
printf("0x%lx", (uintptr_t) -1); → 0xffffffffffffffff
但是,当我从刚分配的对象打印指针时,结果显示的宽度并不相同:

printf("%p", (void*) &myobject); → 0x70d940
我的所有对象(总是)在内存空间开始时都有一个地址,这有什么原因吗?多亏了虚拟内存(从程序的角度来看),它基本上可以放在64位空间的任何地方

另外,为什么默认情况下,
%p
不打印全宽?(我希望它的行为像
0x%016lx

编辑:还有,
0x018p
无效的原因吗

error : fanion « 0 » used with « %p » gnu_printf format

这是因为在大多数C++实现中,指针打印(%P)抑制了前导零,使事物更可读。您可以在打印时使用格式化技巧来获得完整的地址宽度

编辑:我提到的“格式技巧”:

std::cout
<< "0x"
<< std::hex
<< std::noshowbase
<< std::setw(2)
<< std::setfill('0')
<< n
<< std::endl ;
std::cout

如评论中所述


%p
可以选择任何方式格式化地址。它不必是十六进制(尽管通常是);输出不必启动
0x
0x
;它可以用大写或小写打印十六进制

尝试
printf(“%p\n”,(void*)0)
-在Mac电脑上,即使其他值以0x1234样式打印,也只打印
0
。尝试
printf(“%p\n”,(void*)1024)-它可能打印一个短地址
0x400

标准(POSIX或C或C++)中没有规定
%p
的输出应该是什么样子的要求

如果要控制指针的格式,请使用
中的
uintptr\t
PRIzPTR
宏:


如果您喜欢小写十六进制数字,请使用
PRIxPTR
。我不喜欢,而且我确实喜欢
0x
前缀,所以当我不受其他人可疑的感觉约束时,我会使用前缀。

通过
%p
格式说明符的指针的精确表示是实现定义的

根据本规范第7.21.6.1节:

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

特别是在Linux上,声明如下:

void*
指针参数以十六进制打印(就像
%\x
%\lx

因此如果您使用的是Linux,那么可能可以使用
%#016lx

然而,这只是一个实现,所以您不能对C应用程序中的格式做任何假设


例如,在DOS上运行的Turbo C上,指针实际上包含两个值,一个段和一个偏移量。

主要从C的角度讲,因为您已经标记了[C],并且正在使用C风格的代码

如果我没有弄错的话,在64位机器上,指针相当于0到2^64-1之间的数字

这有点棘手。指针可以转换为整数,也可以转换回整数,但未指定整数类型能够支持所有可能的往返指针-整数-指针转换而不丢失数据所需的大小。实现不需要提供这样的类型

此外,指针不需要表示为平面地址空间中的整数索引,事实上,在历史上,一些实现使用了不同的表示。因此,断言指针等同于数字是不正确的,也不安全的,无论其范围如何

还请注意,这

。。。是不安全的,因为它假定
uintpttr\u t
无符号长整数
,但决不能保证是这种情况。为
uintptr\u t
类型的值编写格式字符串的安全方法是:

printf("0x%" PRIxPTR, (uintptr_t) -1);
(使用
inttypes.h

我的所有对象(总是)在内存空间开始时都有一个地址,这有什么原因吗?多亏了虚拟内存(从程序的角度来看),它基本上可以放在64位空间的任何地方

<>这远远超出了C或C++所指定的任何东西,但是,在虚拟内存机上,对象可以放在系统的虚拟地址空间中的任何位置。然而,他们为什么要这样做呢?如果您的对象是动态分配的或具有自动持续时间,那么它们很可能被分配在相对一致的区域中,因为系统具有用于这些目的的区域。如果对象具有静态持续时间,那么原则上它们可能会受到影响,但这取决于系统、C实现、编译选项和其他细节

另外,为什么%p在默认情况下不打印全宽?(如果行为像0x%016lx,则我希望如此)

为何要这样做呢?你的期望是没有道理的
printf()
通常不打印前导零,除非您明确要求它这样做。C甚至不要求将输出格式化为十六进制数——该格式完全由实现定义

编辑:还有,
0x018p
无效的原因吗

error : fanion « 0 » used with « %p » gnu_printf format
因为标准明确规定,当与
p
转换说明符一起使用时,
0
标志字符会导致未定义的行为。更一般地说,当与任何转换说明符一起使用时,它产生UB,而不是
d
i
o
u
x
a
a
e
e
f
f
g
,或
g
。这是一个很长的说明符列表,但是
p
不在其中。如果你仔细看,你会发现所有的都是
printf("0x%" PRIxPTR, (uintptr_t) -1);
printf("%d", INT_MIN);
// "-2147483648"   example
printf("%d", 123);
// "123", not "+0000000123"

double value_nearest_one_seventh = 1/7.0;
printf("%f", value_nearest_one_seventh);
// "0.142857" 
// instead of its exact value of
// 0.142857142857142849212692681248881854116916656494140625
void *ptr = ptr;
int pointer_print_width = sizeof("0xffffffffffffffff") - 1;
printf("<%*p>", pointer_print_width, ptr);
// <          0x28cc6c>