这是有效的 ANSI C++代码?尝试在编译时生成结构成员的偏移量
#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附近的地址空间。我说过:获取成员的地址不会访问、触摸或读取该成员的值。根据标准,它是完全安全的。
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 附近的内存?
我知道有一种安全的方法来计算标准提供的偏移量,但我很好奇你对此有何看法。所有人都赞成我的解释:对这个问题投赞成票:-)
Possible Duplicates:
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);
I had a little chat/conversation with some fellow users, and one of them said that this is dereferencing and accessing the address space near address NULL. I said: taking an address of a member will not access, touch, or read the value of that member. According to standard it is completely safe.
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!
Is this always a safe way to calculate offset, or are compilers free to dereference and mess up the memory near address NULL according to standards?
I know there is a safe way to calculate offsets provided by the standard, but I am curious what you have to say about this. All in favor of my explenation: up-vote this question :-)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
您不会在这里取消引用任何无效的内容。该宏所做的只是告诉编译器,内存中地址
NULL
处存在p_type
类型的结构。然后它获取p_member
的地址,它是这个虚构结构的成员。因此,在任何地方都不会取消引用。事实上,这正是
offsetof
宏的内容,在stddef.h
中定义。编辑:
正如一些评论所说,这可能不适用于 C++ 和继承,我只在 C 中将
offsetof
与 POD 结构一起使用。You're not dereferencing anything invalid here. All that macro does is tell the compiler that a structure of type
p_type
exists in memory at the addressNULL
. It then takes the address ofp_member
, which is a member of this fictitious structure. So, no dereferencing anywhere.In fact, this is exactly what the
offsetof
macro, defined instddef.h
does.EDIT:
As some of the comments say, this may not work well with C++ and inheritance, I've only used
offsetof
with POD structures in C.绝对不是。甚至通过向 NULL 添加偏移量来创建指针也会调用未定义行为。更有动力的人可以从规范中挖掘章节和诗句。
顺便说一句,无论您想要计算这些偏移量的原因是什么,它都可能是一个糟糕的原因。
Absolutely not. To even create a pointer by adding an offset to NULL is to invoke Undefined Behavior. Someone more motivated can dig up chapter and verse from the spec.
By the way, whatever your reason is for wanting to compute these offsets, it is a probably a bad one.
这是无效的 C++。
来自 ISO/IEC 14882:2003, 5.2.5:
但是, 有一个关于此的缺陷报告,并且它是有效的 C99(也可能是有效的 C++0x):
来自 ISO/IEC 9899:1999, 6.5.3:
It is invalid C++.
From ISO/IEC 14882:2003, 5.2.5:
However, there has been a defect report about this, and it is valid C99 (and probably valid C++0x too):
From ISO/IEC 9899:1999, 6.5.3:
所以
&p->b
是&(p->b)
是(根据定义)&((*p).b)
,这似乎确实涉及在获取成员之前取消对p
的引用。即使它违反了标准,它也可以在大多数编译器上运行。正如评论中所指出的,这项工作可能在涉及多重继承的情况下工作正常。您想通过偏移量来解决什么问题?您可以使用引用、指针或成员指针来代替吗?
So
&p->b
is&(p->b)
is (by definition)&((*p).b)
, which does seem to involve a dereference ofp
before getting the member. It may work on most compilers though even if it violates the standard. As noted in a comment this work probably work right in cases involving multiple inheritance.What problem are you trying to solve by getting this offset? Could you use references, pointers, or pointers-to-member instead?
与(预处理后)相同,
我看到您正在将 NULL 转换为指向结构体 a 的指针,然后获取其成员 b 的地址。
据我所知,由于您获取的是 b 的地址,而不是实际访问或修改(取消引用)b 的值,因此编译器不会抱怨,并且您不会收到运行时错误。由于 NULL(或 0)是 a 的起始地址,因此这将为您提供偏移量。这实际上是一个非常巧妙的方法。
Is the same as (after preprocessing)
I see that you are casting NULL to a pointer-to-struct a, and then getting the address of its member b.
As far as I know, since you are getting the address of b, and not actually accessing or modifying (dereferencing) the value of b, the compiler will not complain, and you will not get a runtime error. Since NULL (or 0) is the starting address of a, this will give you the offset. This is actually a pretty nifty way to do that.