6

我最近尝试通过将几个指针的值打印到控制台来调试一个小程序。第一个是结构的内存地址,其他是其字段的内存地址。代码的精简版本如下:

#include <iostream>

struct testingPointers
{
    int i;
    float f;
    double d;
} test;

int main()
{
   std::cout << &test << '\n' << &(test.i) << '\n' << 
            &(test.f) << '\n' << &(test.d);
}

输出是:

0x681110
0x681110
0x681114
0x681118

(显然,不同运行的确切值不同,但它们之间的相对位置始终相同)。

我很困惑,因为第一个指针的值——内存位置——与第二个指针的值test(的第一个字段test)相同。这是否意味着对象没有真正唯一的内存地址,并且指向结构或类的指针只是指向其第一个字段?如果是这样,语句如何

a.b
a->b
a.b()

a如果实际上只是它的第一个字段,因此没有任何字段或方法,是否有意义?

4

4 回答 4

7

对象的地址应始终是该对象中第一个非静态成员的地址。引用标准(C++11-9.2-20):

指向标准布局结构对象的指针,使用 reinterpret_cast 适当转换,指向其初始成员(或者如果该成员是位字段,则指向它所在的单元),反之亦然。[注意:因此,标准布局结构对象中可能存在未命名的填充,但不是在其开头,这是实现适当对齐所必需的。

此处提到了标准布局的要求: StandardLayoutType

这当然可以通过嵌套来应用。位域外,该标准对第一个成员的类型没有任何例外。IE:

class X
{
public:
    int x;
};

class Y
{
public:
    X x;
    int y;
};

Y yobj;

按照标准,&yobj == &yobj.x == &yobj.x.x.

于 2012-11-20T23:58:13.367 回答
5

一个类或结构只是描述了一个字段的集合,这些字段应该一起保存在内存中,并且在它们之间具有某种语义关系以及对它们进行操作的一些操作。在简单的情况下,内存中类类型对象的内容只不过是由它组成的成员(和一些填充)。当您testingPointers在内存中有一个对象时,它实际上只是一个int、 afloat和 a double。类的概念仅用于生成正确的可执行代码——它在运行时不存在(至少不用于此目的)。

标准中关于对象是否可以共享内存地址的重要部分是§1.8/6:

除非对象是位域或大小为零的基类子对象,否则该对象的地址就是它占用的第一个字节的地址。如果一个对象是另一个的子对象,或者如果至少一个是大小为零的基类子对象并且它们属于不同类型,则两个不是位域的对象可能具有相同的地址;否则,它们应具有不同的地址。

我们可以由此推断,因为 membertest.i是 的子对象test,所以它们很可能具有相同的地址。

一旦您尽可能深入地查看程序的所有对象,您真正拥有的是大量标量值和相邻位域。这些在标准中被称为内存位置。这些是真正占用空间的东西。您的其余对象都以某种方式由这些组成。

内存位置要么是标量类型的对象,要么是所有具有非零宽度的相邻位域的最大序列。[注意:语言的各种特性,例如引用和虚函数,可能涉及程序无法访问但由实现管理的额外内存位置。——尾注]

于 2012-11-20T23:47:54.127 回答
3

只是为了澄清你的困惑:

1).第一个指针的值——test 的内存位置——与第二个指针的值(test 的第一个字段)相同。
Struct 的地址和它的第一个字段必须相同,因为 struct 不是其字段的连续集合。

在此处输入图像描述

您还可以考虑数组的情况以进一步简化理解,其中数组的地址显然等于数组的第一个元素(字段)。

2).这是否意味着对象没有真正的唯一内存地址,并且指向结构或类的指针只是指向其第一个字段?
我认为您将它与 JAVA 混淆了,其中对象总是在堆上分配。在 C++ 中,结构/类总是在堆栈上分配,除非它是动态内存分配(使用“new”运算符),其中对象在堆中分配,并且指针变量(在堆栈中)将指向堆中的该对象。因此,在前一种情况下,结构变量将始终具有与其第一个元素(字段)相同的地址。

希望有帮助。

于 2012-11-21T00:38:57.090 回答
1

内存中的结构仅由串在一起的字段组成。根据对齐需要,结构之前和/或字段之间可能有填充,但在第一个字段之前通常没有任何额外的“东西”。所以第一个字段和结构本身具有相同的地址。

请记住,在 C 中,类型仅在编译时存在。

于 2012-11-20T23:48:41.013 回答