gpt4 book ai didi

c - “container_of”宏是否可以严格遵循?

转载 作者:太空狗 更新时间:2023-10-29 16:39:06 25 4
gpt4 key购买 nike

Linux内核(和其他地方)中常用的宏是container_of,其(基本上)定义如下:

#define container_of(ptr, type, member) (((type) *)((char *)(ptr) - offsetof((type), (member))))

它基本上允许在给定指向其成员之一的指针时恢复“父”结构:
struct foo {
char ch;
int bar;
};
...
struct foo f = ...
int *ptr = &f.bar; // 'ptr' points to the 'bar' member of 'struct foo' inside 'f'
struct foo *g = container_of(ptr, struct foo, bar);
// now, 'g' should point to 'f', i.e. 'g == &f'

但是,还不完全清楚 container_of中包含的减法是否被视为未定义的行为。
一方面,因为 bar内部的 struct foo只是一个整数,所以只有 *ptr才应该有效(以及 ptr + 1)。因此, container_of有效地生成类似于 ptr - sizeof(int)的表达式,这是未定义的行为(即使没有解引用)。
另一方面,C标准第6.3.2.3 p.7条规定,将指针转换为不同类型并再次转换应产生相同的指针。因此,将指针“移动”到 struct foo对象的中间,然后返回到开始处应该会产生原始指针。
主要关注的是允许在运行时检查实现越界索引的事实。我对这个和前面提到的指针等价性要求的解释是,必须在指针类型转换中保留边界(这包括指针衰减——否则,如何使用指针在数组中迭代?).ergo,虽然 ptr可能只是一个 int指针,而且 ptr - 1*(ptr + 1)都不是有效的, ptr仍然应该有某种处于结构中间的概念,这样 (char *)ptr - offsetof(struct foo, bar)才是有效的(即使指针实际上等于 ptr - 1)。
最后,我发现如果你有这样的东西:
int arr[5][5] = ...
int *p = &arr[0][0] + 5;
int *q = &arr[1][0];

尽管取消引用 p是未定义的行为,但指针本身是有效的,并且需要与 q进行比较(请参见 this question)。这意味着 pq比较相同,但在某些实现定义的方式上可能不同(这样只有 q才能被取消引用)。这可能意味着,鉴于以下情况:
// assume same 'struct foo' and 'f' declarations
char *p = (char *)&f.bar;
char *q = (char *)&f + offsetof(struct foo, bar);

pq比较相同,但可能具有不同的关联边界,因为 (char *)的强制转换来自指向不兼容类型的指针。
综上所述,c标准对这类行为并不完全清楚,试图应用标准的其他部分(或者至少我对它们的解释)会导致冲突。那么,是否有可能以严格一致的方式定义 container_of?如果是,上述定义是否正确?
在评论了 heremy answer问题之后,我们讨论了这个问题。

最佳答案

我认为它严格符合标准,否则标准有很大缺陷。参考上一个例子,关于指针算术的部分没有给编译器任何余地来区别对待pq。它不取决于指针值是如何获得的,只取决于指针指向的对象。
在指针算法中,任何pq可以被不同对待的解释都需要pq不指向同一对象的解释。因为在获取pq的方式中没有依赖于实现的行为,所以这意味着它们不会指向任何实现上的同一个对象。这反过来要求p == q在所有实现上都是false,因此会使所有实际实现不一致。

关于c - “container_of”宏是否可以严格遵循?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25296019/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com