C++非容器起始地址

C++ Non-Pod starting address

本文关键字:地址 C++      更新时间:2023-10-16

在C中,结构的第一个元素与结构本身具有相同的地址。 如果第一个元素是 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'的无效访问......也许偏移宏使用不正确"警告。

我的问题是 - 我可以假设"节点"位于 foo 的开头(同一地址),即使这是一个非 POD 结构?

如果是,我可以使用重新解释转换,并且没有收到警告:

struct foo *o = reinterpret_cast<struct foo*>(ptr);

那么,如果C++结构以公共 POD 数据开头,第一个元素是否会根据标准共享对象的地址?

谢谢

--编辑-- 在没有虚拟方法或超类的类中,假设(第一个成员变量的地址)== this是否安全?被指出为可能的答案。 它提到"在没有干预访问说明符的情况下声明的(非联合)类的非静态数据成员被分配,以便以后的成员在类对象中具有更高的地址。 这并没有真正解决我案例中的第一个元素是否与对象本身的地址相同。

我认为由于标准没有对此进行任何说明,因此我不能假设是这种情况。 我可能需要将结构末尾的对象更改为指针,并根据需要处理分配它们。

标准在 [class.mem]/19 中说

如果标准布局类对象具有任何非静态数据成员,则其地址与其第一个非静态数据成员的地址相同。否则,其地址与其第一个基类子对象(如果有)的地址相同。[ 注意:因此,标准布局结构中可能存在未命名的填充 对象,但不是在开始时,因为需要实现适当的对齐。—尾注 ]

因此,如果类是标准布局类,而您的类不是标准,则保证第一个成员的地址是类的地址。 在您的情况下,它声明它是它的第一个基类的地址。 由于您没有基对象,这意味着第一个成员共享对象的地址,因为对象开头永远不能有填充。 这意味着foo的地址是其bar成员的地址,并且由于bar是标准布局类,因此它也将是p1的地址。

请注意,尝试在第一个成员之后获取任何成员是未定义的行为。 类类型(包括struct)允许在类的任何成员之间填充以进行对齐。 这意味着您永远不知道其他成员相对于第一个成员的确切位置。

根据 Slava 的说法,因为虚拟表可以是结构的一部分,所以简短的答案是否定的。现在 vtables 不是标准的一部分。它们只是实现虚拟事物的一种机制,从而实现多态性。出于所有实际原因,答案仍然是否定的。

请参阅以下代码:

#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编译的。问题是我认为您没有为p1p2分配内存.