C++ 指向结构或类的指针与指向第一个字段的指针

C++ 指向结构或类的指针与指向第一个字段的指针,c++,oop,pointers,struct,field,C++,Oop,Pointers,Struct,Field,我最近试着通过将几个指针的值打印到控制台来调试一个小程序。第一个是结构的内存地址,其他是其字段的内存地址。代码的精简版本如下所示: #include <iostream> struct testingPointers { int i; float f; double d; } test; int main() { std::cout << &test << '\n' << &(test.i) <

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

#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);
}
(很明显,不同运行的精确值不同,但它们之间的相对位置始终相同)

我很困惑,因为第一个指针的值——
test
的内存位置——与第二个指针的值(test的第一个字段)相同。这是否意味着对象没有真正的唯一内存地址,而指向结构或类的指针只是指向它的第一个字段?如果是这样的话,你的陈述是什么样的

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

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

类或结构只是描述了一组字段,这些字段应该保存在内存中,并且在它们和对它们进行操作的一些操作之间有一些语义关系。在这个简单的例子中,除了由类类型对象组成的成员(和一些填充)之外,内存中的类类型对象的内容没有更多的内容。当内存中有一个
testingPointers
对象时,它实际上只是一个
int
、一个
float
和一个
double
。类的概念仅用于生成正确的可执行代码——它在运行时不存在(至少不用于此目的)

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

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

我们可以由此推断,由于成员
test.i
test
的子对象,它们很可能具有相同的地址

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

内存位置要么是标量类型的对象,要么是相邻位字段的最大序列,所有这些字段的宽度都不为零。[注:语言的各种功能,如引用和虚拟函数,可能涉及程序无法访问但由实现管理的附加内存位置。-结束注]


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


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

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

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

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

这当然可以通过嵌套应用。除了位字段外,本标准对第一个成员的类型没有例外。即:

class X
{
public:
    int x;
};

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

Y yobj;

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

只是为了澄清您的困惑:

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

还可以考虑数组的情况,以进一步简化理解,其中数组的地址显然等于数组的第一个元素(字段)。 2)。这是否意味着对象没有真正的唯一内存地址,而指向结构或类的指针只是指向其第一个字段?
我认为你把它和java的混淆,其中对象总是在堆上分配。C++中,结构/类总是在堆栈上分配,除非它是动态内存分配(使用‘新’运算符),对象在堆中分配,指针变量(栈)将指向堆中的该对象。因此,在前一种情况下,struct变量将始终与其第一个元素(字段)的地址相同


希望有帮助。

不,它们是不同类型的指针。但是第一个字段位于对象的开头。因此它具有相同的起始地址。(除非开头有vtable指针或其他东西。)如果指向我头顶的指针也是指向我头顶的指针,这是否意味着我不存在,因为我真的只是一个脑袋?我从来没有听说过编译器将填充放在第一个成员之前,尽管我不确定它在C中是否被允许。我想它是被允许的(尽管仍然从未见过)在C++中,@ java没有按照标准(92-20)来查看。我在这个帖子的某个地方看到了我的答案。在开始时是不允许的。啊,是的,我可能是用Java来思考的。数组的类比非常有用。+ 1…我在找这个“A”。
class X
{
public:
    int x;
};

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

Y yobj;