为什么不能在C ++中的非POD结构上使用offsetof? [英] Why can't you use offsetof on non-POD structures in C++?
问题描述
我正在研究如何获得一个成员的内存偏移到C ++中的类,并在维基百科中遇到这个问题:
I was researching how to get the memory offset of a member to a class in C++ and came across this on wikipedia:
在C ++代码中,不能使用offsetof访问不是普通数据结构的结构或类的成员。
In C++ code, you can not use offsetof to access members of structures or classes that are not Plain Old Data Structures.
我试过了,它似乎工作正常。
I tried it out and it seems to work fine.
class Foo
{
private:
int z;
int func() {cout << "this is just filler" << endl; return 0;}
public:
int x;
int y;
Foo* f;
bool returnTrue() { return false; }
};
int main()
{
cout << offsetof(Foo, x) << " " << offsetof(Foo, y) << " " << offsetof(Foo, f);
return 0;
}
我有几个警告,但它编译,运行时它给出合理的输出:
I got a few warnings, but it compiled and when run it gave reasonable output:
Laptop:test alex$ ./test
4 8 12
我想我或者误解了POD数据结构是什么,或者我错过了一些其他的谜题。我看不出什么问题。
I think I'm either misunderstanding what a POD data structure is or I'm missing some other piece of the puzzle. I don't see what the problem is.
推荐答案
简短的答案:offsetof是一个只有C ++标准的功能,因此,它基本上限于在C中可以做的东西。C ++只支持它必须为C兼容性。
Short answer: offsetof is a feature that is only in the C++ standard for legacy C compatibility. Therefore it is basically restricted to the stuff than can be done in C. C++ supports only what it must for C compatibility.
由于offsetof基本上是一个黑客)依赖于简单的内存模型支持C,它将需要很多的自由,从C ++编译器实现者如何组织类实例布局。
As offsetof is basically a hack (implemented as macro) that relies on the simple memory-model supporting C, it would take a lot of freedom away from C++ compiler implementors how to organize class instance layout.
效果是, offsetof通常会在C ++中工作(取决于源代码和编译器),即使在没有标准支持的地方,除非它没有。所以你应该非常小心在C ++中使用offsetof,特别是因为我不知道一个编译器会生成一个警告非POD使用...
The effect is that offsetof will often work (depending on source code and compiler used) in C++ even where not backed by the standard - except where it doesn't. So you should be very careful with offsetof usage in C++, especially since I do not know a single compiler that will generate a warning for non-POD use...
< b>编辑:如您要求的示例,以下可能会澄清问题:
Edit: As you asked for example, the following might clarify the problem:
#include <iostream>
using namespace std;
struct A { int a; };
struct B : public virtual A { int b; };
struct C : public virtual A { int c; };
struct D : public B, public C { int d; };
#define offset_d(i,f) (long(&(i)->f) - long(i))
#define offset_s(t,f) offset_d((t*)1000, f)
#define dyn(inst,field) {\
cout << "Dynamic offset of " #field " in " #inst ": "; \
cout << offset_d(&i##inst, field) << endl; }
#define stat(type,field) {\
cout << "Static offset of " #field " in " #type ": "; \
cout.flush(); \
cout << offset_s(type, field) << endl; }
int main() {
A iA; B iB; C iC; D iD;
dyn(A, a); dyn(B, a); dyn(C, a); dyn(D, a);
stat(A, a); stat(B, a); stat(C, a); stat(D, a);
return 0;
}
当尝试定位
内部类型
B
静态,而当实例可用时它工作。这是因为虚拟继承,其中基类的位置存储在查找表中。
This will crash when trying to locate the field a
inside type B
statically, while it works when an instance is available. This is because of the virtual inheritance, where the location of the base class is stored into a lookup table.
虽然这是一个假设的例子,一个实现可以使用查找表也找到类实例的public,protected和private部分。或者使查找完全动态(使用字段的哈希表)等。
While this is a contrived example, an implementation could use a lookup table also to find the public, protected and private sections of a class instance. Or make the lookup completely dynamic (use a hash table for fields), etc.
标准通过将offsetof限制为POD使用POD结构体的散列表...:)
The standard just leaves all possibilities open by restricting offsetof to POD (IOW: no way to use a hash table for POD structs... :)
另一个注意事项:对于这个例子,我不得不重新实现offsetof(这里:offset_s)我为虚拟基类的字段调用offsetof。
Just another note: I had to reimplement offsetof (here: offset_s) for this example as GCC actually errors out when I call offsetof for a field of a virtual base class.
这篇关于为什么不能在C ++中的非POD结构上使用offsetof?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!