C++非POD启动地址

C++非POD启动地址,c++,struct,offsetof,C++,Struct,Offsetof,在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 ba

在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”的访问无效。。。可能offsetof宏的使用不正确

我的问题是——即使这是一个非POD结构,我是否可以假设“node”位于foo相同地址的开头

如果是,我可以使用一个重新解释的演员阵容,我没有得到任何警告:

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

这样,如果C++结构从公共POD数据开始,第一个元素是否会按照标准? 谢谢

-编辑- 有人指出这是一个可能的答案。它提到了非联合类的非静态数据成员在声明时没有插入访问说明符,因此这些成员在类对象中具有更高的地址。这并不能真正解决我的例子中的第一个元素是否与对象本身的地址相同


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

根据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编译的。问题是我认为您没有为p1和p2分配内存。

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

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

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


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

声明struct类型的变量时不需要struct。From:具有不同访问控制的成员按未指定的顺序分配编译器可能会将它们组合在一起-因此这意味着您不能保证分配了bar,因为第一个memberstruct可能具有虚拟表指针,并且我知道在某些平台上是匹配的刚开始的时候。所以不。@UnholySheep-假设没有私有成员,但是一些非POD元素,比如具有自己的public/private的对象,是我的结构的一部分。这将使我的结构非POD,但所有结构都具有相同的访问控制。我可以保证节点在开始位置吗?可能是重复的,这应该显示什么?它是如何回答关于标准的问题的呢?@unholyseep好吧,pedantic flag确保该代码符合标准并且没有问题。只是OP没有写正确谢谢你的评论,但是p1和p2的分配是不相关的,它们作为指针存在。@Marc我写这篇文章是为了解释我对NULL对象的非静态数据成员“foo::node”的访问无效。。。可能offsetof宏的使用不正确。在您的问题中。@user902384-这并没有解决标准实际说明的问题,例如,对于非标准布局,起始地址是否与第一个元素相同。因此,如果bar类似于:struct foo{struct bar node;int a;objectx X;objecty Y Y;};我可以从节点的reinterpret_转换中获得foo的地址,但之后就什么都没有了?我不确定的是:reinterpret_将对象的指针/地址转换为它的第一个非静态成员应该会违反严格的别名规则,不是吗?或者这属于AliasedType和DynamicType的范畴吗?它们可能都是多级的,可能在每个级别都是cv限定的,从引用指向同一类型T的指针page@M
是的。如果foo是struct foo{struct bar node;int a;objectx X;objecty Y;};然后它将是一个标准布局类型,&foo_对象和&foo.object.node将是相同的地址。您知道a的地址是什么,因为节点和a之间可能有填充。请注意,多态性要小心:从子类到父类的转换实际上会更改访问地址&Parentobj=&obj检测它是相关的,但并不总是琐碎的。@NathanOliver不会构造foo{struct bar node;int a;objectx;objecty Y;};如果objectx和objecty是具有相同访问控制的基本对象,则只能使用标准布局类型?我关心的是objectx有公共部分和私有部分。