malloc是否只分配内存,而不分配其他内存?

malloc是否只分配内存,而不分配其他内存?,c,malloc,C,Malloc,首先是代码: struct yo { char *name; int several[10]; int num; }; int main(void) { struct yo *test_yo = malloc(sizeof(struct yo)); printf("%p\t%p\t%p\n", (void *)&test_yo->name, (void *)&test_yo->num, (void *)&test_yo

首先是代码:

struct yo
{
    char *name;
    int several[10];
    int num;
};

int main(void)
{
    struct yo *test_yo = malloc(sizeof(struct yo));
    printf("%p\t%p\t%p\n", (void *)&test_yo->name, (void *)&test_yo->num, (void *)&test_yo->several);
    return 0;
}

我的问题是:如果malloc只分配一些内存空间并返回一个指向它的指针,那么test_-yo如何找到它的名称、num和几个的地址——因为test_-yo只是一个指向一堆垃圾的指针?malloc是否真的在这里做了一些额外的工作,比如对齐结构成员并记录成员的内存地址?

编译器会解决这个问题。i、 e.
sizeof
计算出所需的空间,编译器计算出如何排列内存中的各种项目函数本身不会对齐结构的成员,这是在程序运行之前很久由编译器完成的。例如,在具有八字节指针和四字节整数的系统上,很可能:

  • name
    将位于结构的开头
  • 几个
    将位于偏移量8处;及
  • num
    将位于偏移量48处(允许
    多个
    具有十个四字节元素)
malloc所能做的就是给你一些至少足够大的内存来放入这个结构(或者如果它找不到足够的内存就给你空值)


结构中字段的定位由访问所述结构的代码完成。

malloc仅分配内存。C编译器在编译时知道结构“yo”包含三个字段,包括一个名为“name”的字段,该字段位于结构偏移量0处,等等


因此,编译器接受从malloc返回的指针,添加已知的结构字段偏移量,最终得到描述的直接指向成员的地址。

这与malloc无关。发生的事情非常简单-通过指针X引用结构成员只是向存储在指针X中的内存地址(其值)添加一个偏移量。因此,只需将偏移量应用于malloc返回的指针

记住,编译后的二进制文件中不存在结构——它只是高级编程语言的编译时“概念”。甚至可以使用宏获取结构的每个成员的偏移量

因此,从何处获取指针及其值并不重要,您始终可以通过将其偏移量(编译器始终知道)添加到指针中存储的值来计算结构“字段”的地址

下面是一个小例子来说明这一点:

#include <stddef.h>
#include <stdio.h>

struct my_struct {
        int x;
        int y;
};

int main()
{
        struct my_struct *s;

        /* Print relative offsets of the structure member fields: */
        printf("Offset of 'x': %lu\n", offsetof(struct my_struct, x));
        printf("Offset of 'y': %lu\n", offsetof(struct my_struct, y));

        /*
         * Assign some random memory address to a pointer and print addresses
         * of the structure and its members. You can see that they are related,
         * pointer to 'x' will always be the same as pointer to structure +
         * `offsetof(struct my_struct, x)` and pointer to 'y' as pointer to
         * structure + `offsetof(struct my_struct, y)`
         */
        s = (void *)0xDEADBEEF;
        printf("Pointer to structure: %p\n", s);
        printf("Pointer to x: %p (x - base = %ld)\n",
               &s->x, (ptrdiff_t)&s->x - (ptrdiff_t)s);
        printf("Pointer to y: %p (y - base = %ld)\n",
               &s->y, (ptrdiff_t)&s->y - (ptrdiff_t)s);

        return 0;
}
请注意,您始终可以在运行时计算和字段偏移。与
offset of
的主要不同之处在于,它可用于计算中的偏移量

此外,在尝试自己计算场偏移时要小心。尽管编译器不能重新排列字段,但它可以很容易地执行,有效地在字段成员之间添加隐式的“空”空间(如果需要)


希望能有帮助。祝你好运

malloc只分配特定数量的内存。它返回一个通用指针(即,
void*

编译器可以看到结构,并知道它的布局

如果您有不同的类型,您将得到不同的值(注意下面的代码使用完全相同的指向堆分配内存的指针)


C中的结构是一个非常。。。嗯。。。结构化内存块。假设主机系统具有32位指针和32位整数,则
name
(指针)将始终位于结构的偏移量0处;
multive
的第一个元素始终位于结构的偏移量4处(偏移量0+{sizeof a pointer});和
num
将始终位于结构的偏移量44处(偏移量4+10*{sizeof an int})。偏移量可能因平台和编译器而异,具体取决于数据类型大小、内存对齐等,但对于给定的平台编译器组合,偏移量始终相同。对于我上面给出的示例,类型为
struct yo
的每个项的长度正好为48字节,例如,
num
始终位于结构中的偏移量44。

编译器执行类型检查后,
struct
只不过是偏移量的集合
malloc
完全不知道数据类型、结构或诸如此类的东西。你不想
sizeof(struct yo)
bytes?这是一个18字节的新块。所以真正发生的是test_yo首先得到地址,然后编译器计算test_yo是指向struct yo的指针,然后编译器将test_yo指向的内存中的不同成员对齐,对吗?@Xufeng:当然
->
运算符只是方便的C语法。如果您知道成员的偏移量,您可以引用不带这些运算符的成员(这是在汇编中编程的人必须做的事情)。@Xufeng:我想稍微纠正一下措辞,因为当您通过指针引用字段成员时,编译器不会对齐任何内容。当它第一次看到一个声明时,它会调整结构——在这一点上它决定每个字段的偏移量。当你通过指针引用一个成员时,它只应用之前计算的偏移量。如果是这样,当编译器第一次看到结构时,它会对齐结构并定义它的所有成员?这就是为什么即使我只创建一个指向整个结构的指针,我也可以引用它的成员?@Xufeng:是的,你差不多明白了。
$ clang -Weverything -o test ./test.c && ./test
Offset of 'x': 0
Offset of 'y': 4
Pointer to structure: 0xdeadbeef
Pointer to x: 0xdeadbeef (x - base = 0)
Pointer to y: 0xdeadbef3 (y - base = 4)
struct foo { int i, j, k };
struct bar { char i, j, k; };
void *ptr = malloc(100);
struct foo * fooptr = (struct foo *)ptr;
struct bar * barptr = (struct bar *)ptr;
printf("foo: %p, %p, %p\n", &fooptr->i, &fooptr->j, &fooptr->k);
printf("bar: %p, %p, %p\n", &barptr->i, &barptr->j, &barptr->k);