指针和结构类型的大小看似不一致的原因是什么?

What is the reason for seemingly inconsistent sizes of pointers and struct types?

在我的机器上,相关尺寸是:
sizeof(char) == 1sizeof(int) == 4sizeof(char*) == 8

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

typedef struct person{
    char *name;
    int age;
}Person;

int main()
{
    printf("sizeof(Person): %d\n", sizeof(Person)); //-> 16 bytes
    Person *person = (Person*)malloc(sizeof(Person));
    printf("sizeof(person): %d\n", sizeof(person)); //-> 8 bytes ( Why 8 and not 16? )

    char buffer[32];
    printf("sizeof(buffer): %d\n", sizeof(buffer)); //-> 32 bytes
    person -> name = (char*)malloc(sizeof(buffer));
    printf("sizeof(person->name): %d\n", sizeof(person->name)); //-> 8 bytes ( Why 8 and not 32? )

    return 0;
}

我知道 sizeof(Person) == 16 因为填充,但我不明白以下内容。
如果 sizeof(Person) == 16,为什么 sizeof(person) == 8 而不是 16?
如果 sizeof(buffer) == 32,为什么 sizeof(person->name) == 8 而不是 32?

因为,如sizeof(char *)sizeof(person)、returns指针的大小。在您的情况下,指向结构的指针(此处指向 Person 结构)的大小为 8。

sizeof(person->name) returns char as name 上指针的大小被定义为char *.

buffer不是指针,是数组。编译器知道它和 sizeof(buffer) returns 数组的大小,即使数组的名称和指针之间有一些相似之处,它们也不会被相同对待。

正如 PSkocik 在评论中提到的那样。

person 是一个指针,与指向 char 的指针大小相同。 person->name.
相同 struct person 是一种类型,大小与 Person 相同。

初学者要输出类型为 size_t 的对象,您应使用转换说明符 zu

printf("sizeof(Person): %zu\n", sizeof(Person));
                        ^^^   

I don't understand the following: If sizeof(Person) == 16, why sizeof(person) == 8 and not 16?

名称Person表示结构

typedef struct person{
    char *name;
    int age;
}Person;

这种类型的对象占用16个字节。

名称person声明为

Person *person = (Person*)malloc(sizeof(Person));

表示一个指针。这个指针占8个字节,指向为Person类型的对象分配的一块内存,占16个字节。

也就是sizeof( Person )sizeof( Person * )相当于sizeof( person )是两个不同的表达方式。

And if sizeof(buffer) == 32, why sizeof(person->name) == 8 and not 32?

名称name同样是指针类型,占用8个字节。它是结构 person 的数据成员,声明为

char *name;

这个指针指向一块动态分配的内存,占用32字节。

注意指针的大小并不取决于它是指向单个对象还是指向数组的第一个元素。那就是你可以为一个非常大的数组分配内存,但是指向分配内存的指针的大小不会根据分配内存的大小而改变。

举个例子

int a[10];

int *p = a;

int b[10000];

int *q = b;

在此示例中,指针 p 和 q 的大小相同。你可以这样写

int a[10];

int *p = a;

int b[10000];

p = b;

指针的大小p在最后一次赋值后不会改变。

这是 C 中的一个核心概念。当你理解它时,就是你的突破时刻。

指针是一个地址。我可以把你家的地址写在一张纸上,纸不需要是你家的大小。

我并不傻,因为我们在 C 中使用 'address' 的方式与现实生活中的概念密切相关。但是 C 指针(地址)是内存中的位置。它们由一些固定字节数的值表示。

好的,邮政系统通过字符块识别您的房子。

在计算机中,我们将内存中的位置标识为字节序列。是的,我们使用字节来存储其他字节的位置。

malloc(sizeof(Person)) return 足以容纳 Person 结构的内存块(指向)的地址。

它没有 return 阻止。这是 'somewhere' 标识,可以 'found',访问,写入和读取使用地址。

pointer/address 不是事物,它是对事物的引用。这里在广义的计算意义上使用 reference,而不是在 C++ 中使用的稍微狭义的意义。

您的机器显然使用 64 位寻址。一个标准字节有 8 位,8 的大小等于 64 位。

C 标准中的某些部分从功能上讨论了指针。它告诉您将 & 应用于合适的表达式 return 是一个指针,可以通过 *-> 取消引用以分别到达事物或事物的一部分。但它也谈到了 'address-of' 运算符(即 &),我相信为什么它使用 & 符号,它是一种程式化的 'a'.

回答问题。 sizeof(person) 是 8 个字节,因为这是 malloc() 为您预留的 16 个字节的地址,用于存储请求的 16 个字节(Person 对象的大小)。

关于person->name的答案是相似的。它是 16 字节的地址,而不是 本身 16 字节。

printf("person: %p\n",(void*)person);会打印出地址。 它的实现定义了它是如何产生的,但它几乎肯定会像 person: 0x7ffca93ce784 (但不同的十六进制值)。 如果您更改其中的值,这不会改变(例如 person->age=50;)。

请注意您需要使用 %zu 输出尺寸的建议。 当您分配完内存后,还要养成调用 free(person); 的习惯。呈现给 free() 任何 malloc() 呈现给你的东西。 如果不是,则无法重用分配给您的内存。这不会影响这个小程序。但是以后会成为问题

我想说,形式化引用和它的引用之间的区别是一个关键的计算概念。标识事物和事物的事物。没有人会认为他们的名字指的是他们而不是他们。但是不知何故,当它全部被抽象到计算中时,您需要有意识地更清楚地理解它们之间的区别。

所有编程语言都有这个,有用的语言都有一些类似指针的概念。在 Java 中它是一个对象变量。那是对对象的引用。不是对象。它甚至会让你滑倒,如果你滥用想要给你一个 NullPointerException。但是我认为Java没有指针!秘密。


你很快就会问的问题是为什么 sizeof(Person) 是 16 而 sizeof(char*)+sizeof(int) 是 12。其他 4 个字节在做什么(你会问)?我不会深入研究它,但结构中可能有 'dead' 字节,可以使事情排列得很好。如果指针和整数之类的东西存储在某些低位设置为 0 的地址中,许多计算机需要(或工作效率更高)——这称为对齐,这是硬件问题!