在C中,struct的第一个元素与struct本身具有相同的地址。如果第一个元素是POD,那么对于C ++中的非POD结构是否同样如此?
例如,给定此代码:
struct bar
{
struct bar *p1, *p2;
unsigned char h;
}
struct foo
{
struct bar node;
int a;
private:
int x;
};
int main(void)
{
struct foo A;
struct bar *ptr;
ptr = &A.node;
struct foo *n = ((struct foo*)((char*)(ptr)-(unsigned long)(&((struct foo*)0)->node)));
return 0;
}
我得到“对NULL对象的非静态数据成员'foo :: node'的无效访问...可能错误地使用了offsetof”警告。
我的问题是这个 - 我可以假设'node'位于foo(同一地址)的开头,即使这是一个非POD结构吗?
如果是,我可以使用重新解释演员表,但我没有收到任何警告:
struct foo *o = reinterpret_cast<struct foo*>(ptr);
因此,如果C ++结构以公共POD数据开头,那么第一个元素是否会按照标准共享对象的地址?
由于
- edit-- In a class with no virtual methods or superclass, is it safe to assume (address of first member variable) == this?被指出是一个可能的答案。它提到“在没有插入访问说明符的情况下声明的(非联合)类的非静态数据成员被分配,以便后面的成员在类对象中具有更高的地址。”这并不能真正解决第一个元素是否存在在我的情况下是与对象本身相同的地址。
我认为既然标准没有说清楚它,我不能认为是这样的。我可能需要将结构末尾的对象更改为指针,并根据需要处理它们。
答案 0 :(得分:1)
标准在[class.mem] / 19
中说如果标准布局类对象具有任何非静态数据成员,则其地址与其第一个非静态数据成员的地址相同。否则,其地址与其第一个基类子对象的地址(如果有)相同。 [注意:因此在标准布局结构中可能存在未命名的填充 对象,但不是在它的开始,为实现适当的对齐所必需的。 - 后注]
因此,如果该类是标准布局类,那么您的标准不是标准保证第一个成员的地址是该类的地址。在你的情况下,它声明它是它的第一个基类的地址。由于您没有基础对象,这意味着第一个成员共享对象的地址,因为在对象的开头永远不会填充。这意味着foo
的地址是bar
成员的地址,因为bar
是标准布局类,它也是p1
的地址。
请注意,尝试在第一个成员之后获取任何成员是未定义的行为。类类型(包括struct
)允许在类的任何成员之间使用填充以进行对齐。这意味着你永远不知道其他成员与第一个成员的确切位置。
答案 1 :(得分:-4)
根据Slava,因为虚拟表可以是struct的一部分所以简短的答案是否定的。现在vtable不是标准的一部分。它们只是实现虚拟事物并因此实现多态的机制。答案仍然没有出于所有实际原因。
请参阅以下代码:
#include <iostream>
using namespace std;
struct bar
{
struct bar *p1, *p2;
unsigned char h;
};
struct foo
{
struct bar node;
int a;
private:
int x;
};
int main(void)
{
struct foo A;
struct bar *ptr;
A.node.p1 = new bar();
A.node.p2 = new bar();
ptr = &A.node;
struct foo *n = ((struct foo*)((char*)(ptr)-(unsigned long)(&((struct foo*)0)->node)));
cout << n->a << endl;
return 0;
}
使用g++ -Wall -Werror -pedantic -std=c++14 test.cpp
编译代码。问题是我认为你没有为p1
和p2
分配内存。