11
int test[2] = { 45, test[0] };
int x = (x = 111);
cout << test[0] << " " << test[1] << " " << x << "\n"; // 45 45 111

前两行中的分配是否合法?Visual Studio 2010 编译和运行它时没有任何错误或警告,但这似乎是一个可能未定义的奇怪情况,所以我想确认它是可以接受的。如果我做了一些公然自反(并且可能是未定义的)的事情,Visual Studio 确实会警告我,int x = x;所以我想知道它似乎允许的这些情况是如何处理的。

4

4 回答 4

5

来自 C++ 标准(C++11,但在 C++98/03 中没有什么不同):

(第 3.3.2/1 节)名称的声明点紧接在其完整声明符(第 8 条)之后和其初始化程序(如果有)之前,[...] [ 示例:

int x = 12;
{ int x = x; }

这里第二个 x 用它自己的(不确定的)值初始化。—结束示例]

这也适用于用户定义的类型以及数组类型。请注意标准如何强调x在第二个示例中使用不确定值进行初始化。所以没有办法知道x初始化的值是什么。

于 2012-11-09T01:07:06.360 回答
1

我假设你在某个函数中,因为你正在调用函数等。

test两者的空间都x分配在堆栈上。理论上,这些家伙的空间在他们的值被填充之前应该存在。如果我们查看生成的程序集(x86 gcc),这是真的。

subl    $40, %esp         # Add 40 bytes of memory to the current stack
movl    $0, -20(%ebp)     # Clear test[0] to 0
movl    $0, -16(%ebp)     # Clear test[1] to 0
movl    $45, -20(%ebp)    # Place the value of 45 into test[0]
movl    -20(%ebp), %eax  # Copy that 45 into a register
movl    %eax, -16(%ebp)  # Move that register's value (45) into test[1]
movl    $111, -12(%ebp)  # Assign x to be 111, optimize out the unnecessary duplicate assignment
    ... #continues on to set up and call printf

我们可以看到堆栈中添加了 40 个字节。请注意 test[0]、test[1] 和 x 的地址是如何%ebp以 4 字节间隔(分别为 -20、-16、-12)标记的连续地址。它们在内存中的位置是存在的,并且在定义之前可以无错误地访问。此处的编译器将它们都清除为 0,尽管我们可以看到这是不必要的。您可以删除这两行并且仍然可以正常运行。

我们可以从中得出的结论是,您的int test[2]int x内部可以有任意数量的时髦循环引用,并且代码将编译——您的工作就是确保您的引用获取良好的数据(即以某种方式初始化数据) 而不是垃圾,你在这里所做的。这也适用于其他情况 - 编译为程序集并自己检查它是如何完成的。

于 2012-11-09T02:57:24.560 回答
0

这是合法的,因为变量的声明在你初始化它的时候就已经完成了。但是, 的值test[1]是未定义的。

于 2012-11-09T00:32:23.773 回答
0

您拥有的所有代码都是完全合法的。甚至在某些情况下,您甚至可能也这样做。

于 2012-11-09T00:32:35.180 回答