C中指针的字节宽度

Width in bytes of a pointer in C

我是动态和静态分配的新手,我注意到一个奇怪的行为。我制作了以下代码片段:

#include ...
int main(void){

    int i ;
    printf(" using amesand :%p\n", &i);
    
    int *j = malloc(sizeof(*j)) ;
    printf(" using malloc :%p\n", j)

}

然后编译并生成:

 using amesand :0x7ffc0128695c
 using malloc :0x6686b0

我在某处读到

all pointers have the same width within the same implementation.

谁能解释一下为什么 malloc() 返回的指针只有 3 个字节长

使用sizeof运算符来确定指针的宽度,例如:

int i;
printf(" using amesand :%zu\n", sizeof( &i ));

int *j = malloc(sizeof(*j));
printf(" using malloc :%zu\n", sizeof( j) );

对于此输出,地址可以具有不同的值,具体取决于相应内存的分配位置。并且使用转换说明符 %p 通常(如您的情况)生成跳过前导零的输出。

all pointers have the same width within the same implementation.

是的,至少对于严格符合 C 的程序。有一些常见的非标准扩展,其中较大的指针与普通指针混合在一起,通常带有非标准关键字 far.

然而,这不是这里的问题,而只是您对 printf 的使用。默认情况下,它会删除前导零。不仅适用于十六进制,而且适用于任何数字。 printf("%d", 1) 打印 1 对吧?而不是 0000000001 只是因为 int 恰好是 4 个字节 = 10 个十进制数字。指针和十六进制没有什么不同,默认情况下会删除前导零,除非您以其他方式告诉函数。

如果你想打印一个与指针大小相对应的十六进制数,你可以使用 %.16p 表示 16 位 = 8 字节大指针。或者 variably/portably,像这样:

printf(" using malloc :%.*p\n", sizeof(j)*2, j);

在 x86_64 Linux 上测试的更正示例:

#include <stdio.h>
#include <stdlib.h>

int main(void){

    int i ;
    printf(" using amesand:\t%.*p\n", sizeof(&i)*2, &i);
    
    int *j = malloc(sizeof(*j)) ;
    printf(" using malloc:\t%.*p\n", sizeof(j)*2, j);
}

输出:

using amesand:  0x00007ffe8710871c
using malloc:   0x0000000000ed82b0

关于为什么不同的内存类型有不同的地址,看这个:

使用 %p,您的 C 实现简单地从指针值中省略前导零。

打印“0x6686b0”并不表示指针是三个字节长;它仅表示值为 6686b016,等于 006686b016、00000000006686b016 或 000000000000000000000000000000000006686b016。前导零已被省略。