无警告地取消初始化结构 [关闭]

问题描述 投票:-1回答:1

有这个。

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

typedef struct {
   int a, b;
} str_t;

int main (void) {

   str_t *abc = (str_t*)((((str_t*)0)->a)-offsetof(str_t,a));

   return 0;
}

我试着用同样的方法来做这个宏。

#define container_of(ptr, type, member) ({                      \
        const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
        (type *)( (char *)__mptr - offsetof(type,member) );}) 

编译器并没有给出任何具体的错误, 但结果程序崩溃了。为什么不崩溃的宏以及?

c pointers language-lawyer
1个回答
0
投票

你真正的问题是关于

typeof( ((struct Foo*)0)->a )    // Relevant code from the macro.

int i = ((struct Foo*)0)->a;     // Relevant code from your program.

让我们从使用一个有效的指针开始吧 p 而不是 0,并自问下面两个片段的作用。

struct Foo s = { 0 };
struct Foo *p = &s;

typeof( p->a )

int i = p->a;

在第一种情况下,我们试图获取一个结构体成员的类型。在第一种情况下,我们试图获取一个结构体成员的类型。p 是不相关的;编译器只需要它的类型。事实上,结果是在编译过程中计算出来的,在 p 被分配或赋值。

在第二种情况下,我们正试图读取内存。这个内存将被找到相对于指针在 p. 不同数值的 p 会导致读取不同的内存位置。


那么当我们使用 0 而不是一个有效的指针?

在第一种情况下,我们从来没有一个有效的指针。因为 typeof 在编译过程中被评估,而当 typeof 被评估。所以这就意味着,下面的内容在概念上可以正常工作。

typeof( ((struct Foo*)0)->a )

这给我们带来了第二种情况

int i = ((struct Foo*)0)->a;

0 意味着 NULL 当使用一个指针时,可能根本不是零。

这就试图在读取内存一些字节后,在 NULL. 但是... NULL 不是一个地址,而是没有地址。从一个相对于地址读取内存的概念。NULL 是有缺陷的,没有意义的。既然概念没有意义,就不可能有好的效果。


标准怎么说呢?typeof( ((struct Foo*)0)->a )?

我不知道啊


什么是标准说 int i = ((struct Foo*)0)->a;?

C语言并没有定义这种情况下会发生什么。我们称之为未定义行为。编译器遇到这种情况时,可以自由地做任何事情。通常情况下,它会导致一个保护故障(在unix系统上会产生一个SIGSEGV信号)。

$ gcc -Wall -Wextra -pedantic a.c -o a     # OP's program
a.c: In function ‘main’:
a.c:11:11: warning: unused variable ‘abc’ [-Wunused-variable]
    str_t *abc = (str_t*)((((str_t*)0)->a)-offsetof(str_t,a));
           ^~~

$ ./a
Segmentation fault (core dumped)
© www.soinside.com 2019 - 2024. All rights reserved.