此问题在此处已有答案:
11年前关闭了。
可能重复:
Does the 'offsetof' macro from <stddef.h> invoke undefined behaviour?
dereferencing the null pointer
#define _OFFS_OF_MEMBER(p_type, p_member) (size_t)&(((p_type *)NULL)->p_member)
struct a
{
int a, b;
};
size_t l = _OFFS_OF_MEMBER(struct a, b);
我和一些同事聊天/交谈过,其中一个说这是解引用和访问地址NULL附近的地址空间。获取成员的地址将不会访问、接触或读取该成员的值。2根据标准,这是完全安全的。
struct a* p = NULL;
size_t offset = &p->b; // this may NOT touch b, it is not dereferencing
// p->b = 0; // now, we are dereferincing: acccess violation time!
这总是一种安全的计算偏移量的方法吗?还是编译器可以根据标准自由地解引用和弄乱内存近地址NULL?
我知道有一种安全的方法来计算标准提供的补偿,但我很好奇你对此有什么要说的。投票赞成这个问题:-)
5条答案
按热度按时间tnkciper1#
它是无效的C++。
摘自ISO/IEC 14882:2003第5.2.5节:
3/如果E1的类型为“指向类X的指针”,则表达式E1-〉E2转换为等价形式(*(E1)). E2(...)
然而,有一个关于这个的缺陷报告,它是有效的C99(可能也是有效的C++0x):
根据ISO/IEC 9899:1999第6.5.3节:
2/如果[一元&运算符的]操作数是一元 * 运算符的结果,则该运算符和&运算符都不求值,结果就像两者都被省略了一样,只是运算符的约束仍然适用,并且结果不是左值。
yftpprvb2#
所以
&p->b
is&(p->b)
is(根据定义)&((*p).b)
,这看起来确实涉及到在获取成员之前对p
的解引用。尽管它违反了标准,但它可能适用于大多数编译器。正如注解中所指出的,这项工作可能适用于涉及多重继承的情况。你想通过获取这个偏移量来解决什么问题?你能用引用、指针或者指向成员的指针来代替吗?
ct3nt3jp3#
与相同(预处理后)
我看到您正在将NULL强制转换为指向结构体a的指针,然后获取其成员b的地址。
据我所知,因为你得到的是B的地址,而不是实际访问或修改(解引用)b的值,所以编译器不会抱怨,你也不会得到运行时错误。因为NULL(或0)是a的起始地址,这会给予你偏移量。这实际上是一个很好的方法。
11dmarpk4#
这里你没有解引用任何无效的东西,这个宏所做的只是告诉编译器
p_type
类型的结构存在于NULL
地址,然后它取p_member
的地址,这是这个虚构结构的一个成员,所以没有解引用。事实上,这正是
stddef.h
中定义的offsetof
宏所做的。编辑:
正如一些评论所说,这可能不适用于C++和继承,我只在C中使用了带有POD结构的
offsetof
。axr492tv5#
当然不是。甚至通过向NULL添加偏移量来 * 创建 * 指针都是调用Undefined Behavior。更有动力的人可以从规范中挖掘章节和诗句。
顺便说一句,不管你想要计算这些偏移量的原因是什么,这可能是一个糟糕的原因。