声明时可以使用变量吗?

Can a variable be used while being declared?

为什么下面的编译没有错误?:

int main()
{
    int x = x;  //I thought this should cause an error
    return 0;
}

标准中哪里解释了为什么允许这样做?

C++14 草案 N4140 [basic.scope.pdecl]/1:

The point of declaration for a name is immediately after its complete declarator (Clause 8) and before its initializer (if any), except as noted below. [ Example:

unsigned char x = 12;
{ unsigned char x = x; }

Here the second x is initialized with its own (indeterminate) value. —end example ]

C++ 的答案——我引用的是 C++11 标准:

3.3.3.1:

A name declared in a block (6.3) is local to that block; it has block scope. Its potential scope begins at its point of declaration (3.3.2) and ends at the end of its block.

而声明点在3.3.2中定义为

The point of declaration for a name is immediately after its complete declarator (Clause 8) and before its initializer (if any), except as noted below.

[ Example:

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

Here the second x is initialized with its own (indeterminate) value. — end example ]

显然,在初始化之前使用 x 的值是未定义的行为。

此问题在 C 中的答案与在 C++ 中的答案略有不同。

在这两种情况下,int x = x; 尝试用自身初始化 x


In C++: [dcl.init]/12 (N3936) 表示对具有不确定值的对象的任何评估都会导致未定义的行为,除了对于 某些涉及无符号char 的情况。事实上有一个 Example:

int f(bool b) {
    unsigned char c;
    unsigned char d = c; // OK, d has an indeterminate value
    int e = d;        // undefined behavior
    return b ? d : 0; // undefined behavior if b is true
}

在C:比较复杂。这与 int b; foo(b - b); 的行为非常相似,即 covered in full here.

我不会重复那段文字,但结论是,在 C11 中:

    当且仅当系统具有 int 的陷阱表示时,
  • int a = a; &a; 才会导致 UB
  • int a = a;,随后没有出现 &a,导致 UB。

历史记录:在 C90 中,这导致了 UB。在 C99 中引入了 trap representation,在 C11 中引入了寄存器陷阱的可能性(针对 Itanium)。 C++ 标准根本不处理陷阱表示,在 生成负零的情况下似乎未指定。

这个问题实际上有两个部分,一个问:

Can a variable be used while being declared?

由于在其他答案中引用了声明规则,因此答案明确为是。

并且,同样重要但未被问及:

What usages of a variable during its declaration are safe?

好吧,在初始化器中,变量还没有完成初始化(对象生命周期的问题),实际上构建甚至还没有开始。对象生命周期规则(标准的第 3.8 节)规定,一些但不是所有的操作都允许对这样的变量进行:

Before the lifetime of an object has started but after the storage which the object will occupy has been allocated or, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, any pointer that refers to the storage location where the object will be or was located may be used but only in limited ways. For an object under construction or destruction, see 12.7. Otherwise, such a pointer refers to allocated storage, and using the pointer as if the pointer were of type void*, is well-defined. Indirection through such a pointer is permitted but the resulting lvalue may only be used in limited ways, as described below. The program has undefined behavior if:

  • the object will be or was of a class type with a non-trivial destructor and the pointer is used as the operand of a delete-expression,
  • the pointer is used to access a non-static data member or call a non-static member function of the object, or
  • the pointer is implicitly converted to a pointer to a virtual base class, or
  • the pointer is used as the operand of a static_cast, except when the conversion is to pointer to cv void, or to pointer to cv void and subsequently to pointer to either cv char or cv unsigned char, or
  • the pointer is used as the operand of a dynamic_cast.

实际上,对于具有非平凡初始化的类型,内存位置还不包含对象,因此它没有动态类型,并尝试以 char 或 [= 以外的任何类型访问它19=] 立即与严格的别名冲突。

对于具有简单初始化的类型,包括 int,一旦获得正确对齐的存储空间,对象就会存在。但是,如果该存储具有自动或动态存储持续时间,则在写入变量之前该值是不确定的。适用第 8.5 节中的此规则:

If no initializer is specified for an object, the object is default-initialized. When storage for an object with automatic or dynamic storage duration is obtained, the object has an indeterminate value, and if no initialization is performed for the object, that object retains an indeterminate value until that value is replaced. [ Note: Objects with static or thread storage duration are zero-initialized, see 3.6.2. — end note ] If an indeterminate value is produced by an evaluation, the behavior is undefined except in the following cases:

并且列出的所有例外情况都特定于 unsigned char

乍一看,这条规则似乎不适用,因为指定了初始化程序。但是,在初始化程序的评估期间,我们恰好处于 "When storage for an object with automatic or dynamic storage duration is obtained" 规则适用的情况。