9
#include <iostream>

using namespace std;

class Empty{
    char omg[0];
};

int main()
{
    Empty em1, em2;
    Empty set[100];
    cout << sizeof(Empty) << " " << sizeof(em1) << " " << sizeof(em2) << endl;
    cout << (long*)&em1 << " " << (long*)&em2 << endl;

    cout << "total numbers of element is: " << sizeof(set)/sizeof(*set) << endl;

    return 0;
}

它的输出是:

0 0 0

0xbff36ad0 0xbff36ac8

元素数量为:4

结果令人惊讶。

如上图,Empty是一个类,它的大小和它的对象都是0,为什么?

也许我猜,因为一个空类的大小是1,当类不为空时,它的大小是由成员决定的,但是这里它的成员是特殊的,它是一个长度为零的数组,而这个数组的大小是0,所以类和对象的大小都是0。

这只是我的猜测。随着程序的运行,我们可以看到两个对象都有地址,而且地址不同。

这里是我的问题:如果可以实现 0 大小的对象,为什么 C++ 标准规定空对象有 sizeof() = 1,它是为了“确保两个不同对象的地址会不同”为什么是大小一个空类不为零?, 但是现在,我们确实有不同的地址作为输出,这是怎么发生的?

更进一步,不管数组集合的大小,最后一行输出总是4,为什么?

谢谢 :)

PS:我在MacOS上运行这个程序,编译器是Apple LLVM 5.1版(clang-503.0.40)(基于LLVM 3.4svn)

4

1 回答 1

1

我会试一试,因为没有人更有经验:

如上图,Empty是一个类,它的大小和它的对象都是0,为什么?

标准禁止零大小的数组,因此就标准而言,这sizeof(Empty)是一个毫无意义的表达,您已经处于未定义行为的领域。

这是我的问题:如果可以实现 0 大小的对象,[...] 为什么空类的大小不为零?, 但是现在,我们确实有不同的地址作为输出,这是怎么发生的?

如上所述,大小为 0 的对象不能存在于有效的标准 c++ 程序中(基类子对象除外)。

您的编译器允许将其作为标准的扩展,并且只要您在其预期的范围内使用此扩展(即作为预灵活数组成员 hack),您应该不会有任何问题,尽管您的代码不是便携的。但是,您上面的示例并不是如何使用零大小的数组(更不用说 C++ 中有更好的构造来处理这些情况)。

您的编译器足够智能,可以为em1和提供单独的地址em2,但您应该发现 的所有元素set实际上具有相同的地址。

更进一步,不管数组集合的大小,最后一行输出总是4,为什么?

由于您的编译器认为sizeof(Empty)和 的数组Empty为零,因此您将除以零,这是未定义的行为。如果您禁用优化,您可能会发现您的程序崩溃,例如使用 GCC,您的程序崩溃-O0但不使用-O1.

于 2014-09-16T12:48:05.150 回答