4

我创建了一个类,但它的大小为零。现在,我如何确定所有对象都有不同的地址?(我们知道,空类的大小不为零。)

#include<cstdio>
#include<iostream>
using namespace std;
class Test
{
    int arr[0];//Why is the sizezero?
};

int main()
{
    Test a,b;  
      cout <<"size of class"<<sizeof(a)<<endl;
       if (&a == &b)// now how we ensure about address of objects ?
          cout << "impossible " << endl;
       else
          cout << "Fine " << endl;//Why isn't the address the same? 

        return 0;
}        
4

4 回答 4

8

你的类定义是非法的。C++ 不允许0在任何上下文中使用大小声明数组。但是,即使您使您的类定义完全为空,sizeof仍然需要计算为非零值。

9/4 类类型的完整对象和成员子对象应具有非零大小。

换句话说,如果您的编译器接受类定义并将上述值评估sizeof为零,则该编译器超出了标准 C++ 语言的范围。它必须是与标准 C++ 无关的编译器扩展。

因此,在这种情况下,“为什么”问题的唯一答案是:因为这就是它在编译器中实现的方式。

我不明白这与确保不同的对象具有不同的地址有什么关系。无论对象大小是否为零,编译器都可以轻松执行此操作。

于 2013-08-31T18:05:07.867 回答
6

该标准说,拥有一个大小为零的数组会导致未定义的行为。当您触发未定义的行为时,标准提供的其他保证(例如要求对象位于不同地址)可能不成立。

不要创建大小为零的数组,你不应该有这个问题。

于 2013-08-31T18:06:10.527 回答
4

This is largely a repetition of what the other answers have already said, but with a few more references to the ISO C++ standard and some musings about the odd behavior of g++.

The ISO C++11 standard, in section 8.3.4 [dcl.array], paragraph 1, says:

If the constant-expression (5.19) is present, it shall be an integral constant expression and its value shall be greater than zero.

Your class definition:

class Test
{
    int arr[0];
};

violates this rule. Section 1.4 [intro.compliance] applies here:

If a program contains a violation of any diagnosable rule [...], a conforming implementation shall issue at least one diagnostic message.

As I understand it, if a compiler issues this diagnostic and then accepts the program, the program's behavior is undefined. So that's all the standard has to say about your program.

Now it becomes a question about your compiler rather than about the language.

I'm using g++ version 4.7.2, which does permit zero-sized arrays as an extension, but prints the required diagnostic (a warning) if you invoke it with, for example, -std=c++11 -pedantic:

warning: ISO C++ forbids zero-size array ‘arr’ [-pedantic]

(Apparently you're also using g++.)

Experiment shows that g++'s treatment of zero-sized arrays is a bit odd. Here's an example, based on the one in your program:

#include <iostream>

class Empty {
    /* This is valid C++ */
};

class Almost_Empty {
    int arr[0];
};

int main() {
    Almost_Empty arr[2];
    Almost_Empty x, y;

    std::cout << "sizeof (Empty)        = " << sizeof (Empty) << "\n";
    std::cout << "sizeof (Almost_Empty) = " << sizeof (Almost_Empty) << "\n";
    std::cout << "sizeof arr[0]         = " << sizeof arr[0] << '\n';
    std::cout << "sizeof arr            = " << sizeof arr << '\n';

    if (&x == &y) {
        std::cout << "&x == &y\n";
    }
    else {
        std::cout << "&x != &y\n";
    }

    if (&arr[0] == &arr[1]) {
        std::cout << "&arr[0] == &arr[1]\n";
    }
    else {
        std::cout << "&arr[0] != &arr[1]\n";
    }
}

I get the required warning on int arr[0];, and then the following run-time output:

sizeof (Empty)        = 1
sizeof (Almost_Empty) = 0
sizeof arr[0]         = 0
sizeof arr            = 0
&x != &y
&arr[0] == &arr[1]

C++ requires a class, even one with no members, to have a size of at least 1 byte. g++ follows this requirement for class Empty, which has no members. But adding a zero-sized array to a class actually causes the class itself to have a size of 0.

If you declare two objects of type Almost_Empty, they have distinct addresses, which is sensible; the compiler can allocate distinct objects any way it likes.

But for elements in an array, a compiler has less flexibility: an array of N elements must have a size of N times the number of elements.

In this case, since class Almost_Empty has a size of 0, it follows that an array of Almost_Empty elements has a size of 0 *and that all elements of such an array have the same address.

This does not indicate that g++ fails to conform to the C++ standard. It's done its job by printing a diagnostic (even though it's a non-fatal warning); after that, as far as the standard is concerned, it's free to do whatever it likes.

But I would probably argue that it's a bug in g++. Just in terms of common sense, adding an empty array to a class should not make the class smaller.

But there is a rationale for it. As DyP points out in a comment, the gcc manual (which covers g++) mentions this feature as a C extension which is also available for C++. They are intended primarily to be used as the last member of a structure that's really a header for a variable-length object. This is known as the struct hack. It's replaced in C99 by flexible array members, and in C++ by container classes.

My advice: Avoid all this confusion by not defining zero-length arrays. If you really need sequences of elements that can be empty, use one of the C++ standard container classes such as std::vector or std::array.

于 2013-08-31T19:41:59.600 回答
1
  • 变量声明和变量初始化是有区别的。在您的情况下,您只需声明变量;A 和 B。一旦你声明了一个变量,你需要使用 NEW 或 MALLOC 来初始化它。
  • 初始化现在将为您刚刚声明的变量分配内存。您可以将变量初始化为任意大小或内存块。
  • A 和 B 都是变量,这意味着您已经创建了两个变量 A 和 B。编译器会将这个变量识别为唯一变量,然后它将 A 分配给一个内存地址,比如 2000,然后将 B 分配给另一个内存地址,比如 150。
  • 如果您希望 A 指向 B 或 B 指向 A,则可以引用 A 或 B,例如;A = & B。现在 A 作为 B 的内存引用或地址,或者更确切地说 A 指向 B。这称为传递变量,在 C++ 中,您可以通过引用传递变量或通过值传递变量。
于 2013-08-31T20:46:25.010 回答