2017-03-17 39 views
1

在C中,结构的第一个元素与结构本身具有相同的地址。如果第一个元素是POD,那么对于C++中的非POD结构也是如此?C++ Non-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对象非静态数据成员‘富::节点’无效访问......也许错误地使用了offsetof宏”警告。

我的问题是这样的 - 我可以假设'node'在foo(同一地址)的开头,即使这是一个非POD结构?

如果是的话,我可以只使用一个重新解释施放,我没有得到任何警告:

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

所以,如果C++结构与公共POD数据开始,对象将在第一元件共享地址每个标准?

感谢

- 编辑 - In a class with no virtual methods or superclass, is it safe to assume (address of first member variable) == this?指出作为一个可能的答案。它提到“在没有插入访问说明符的情况下声明的(非联合)类的非静态数据成员被分配,以便后来的成员在类对象中拥有更高的地址。”这并不真正解决第一个元素在我的情况下是与对象本身相同的地址。

我觉得既然标准没有对它说什么,我不能认为是这样。我可能需要将结构末尾的对象更改为指针,并根据需要处理它们的分配。

+0

在C++中,'struct'不需要用于声明类型结构的一个变量。 –

+2

从[cppreference](http://en.cppreference.com/w/cpp/language/data_members):*“与不同的访问控制成员在未指定的顺序分配(编译器可组在一起)” * - 使得应该意味着你不能保证'bar'被分配为第一个成员 – UnholySheep

+1

'struct'可能有虚拟表指针,并且与我在开始的某个平台上所知道的匹配。所以不行。 – Slava

回答

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

+0

这应该表明什么?它是如何回答这个问题的(具体问题是关于标准)? – UnholySheep

+0

@UnholySheep好吧,迂腐的旗帜确保这些代码符合标准并且没有问题。只是OP没有正确写入 – user902384

+0

谢谢你的评论,但是p1和p2的分配是不相关的(它们作为指针存在)。 – Marc

1

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

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

因此,如果类是标准布局类这你是不是标准保证了第一件的地址是类的地址。在你的情况下,它声明它是它的第一个基类的地址。由于您没有基础对象,这意味着第一个成员共享该对象的地址,因为在对象的开始处永远不会有填充。这意味着foo的地址是它的地址是bar成员,因为bar是一个标准的布局类也将是p1地址。

请注意,虽然在尝试获取任何成员后的第一个成员是不确定的行为。类对象类型(包括struct)允许在类的任何成员之间进行填充以便对齐。这意味着你永远不会知道其他成员与第一名成员的关系。

+0

因此,如果“酒吧”是这样的: 结构FOO { 结构杆节点; int a; objectx X; 对象Y; }; 我可以从“node”的reinterpret_cast中获取“foo”的地址,但是之后没有任何内容? – Marc

+0

我不确定的东西:'reinterpret_cast'把对象的指针/地址改为第一个非静态成员应该打破严格的别名规则,不是吗?或者这属于*的类别“AliasedType和DynamicType都是(可能是多级的,可能在每个级别都被cv限定)指向相同类型的指针T”*(来自['reinterpret_cast'](http:// en.cppreference.com/w/cpp/language/reinterpret_cast)参考页) – UnholySheep

+0

@Marc是的。如果'foo'是'struct foo {struct bar node; int a; objectx X;对象Y; };'那么它将是一个标准的布局类型,'&foo_object'和'&foo.object.node'将是相同的地址。你知道'a'的地址是什么,因为'node'和'a'之间可以有填充。 – NathanOliver