提问人:Ridwan Faiz 提问时间:3/12/2022 最后编辑:Ridwan Faiz 更新时间:3/12/2022 访问量:81
为什么初始化值本身不会在 C 中抛出任何错误?
Why initializing a value by itself is not throwing any error in C?
问:
我在练习 C 语言作业时提出了这个问题。当我尝试使用其名称(标识符)初始化任何变量时,它甚至不存在,不会抛出任何类型的错误。
int x = x;
据我所知,赋值运算符的关联性是从右到左。因此,当我使用甚至不存在的右值初始化变量时,以下代码应该会抛出错误。相反,它正在为它分配某种垃圾值。为什么会这样?
答:
在 c 标准中,将值设置为 本身是未定义的行为。追加编译器选项后,出现警告。-Winit-self
评论
*UART_DR = *UART_DR;
x
-Winit-self
GCC 11.2 确实会在使用 -Wuninitialized -Winit-self
时诊断出此问题。
我怀疑可能被用作成语1,表示“我知道我在做什么;不要警告我未初始化“,因此它被排除在 之外,但提供了单独的警告。int x = x;
x
-Wuninitialized
-Winit-self
请注意,虽然 的行为不是由 C 标准定义的(如果它位于函数内部并且没有采用 的地址),但它也不违反 C 标准的任何约束。这意味着不需要编译器来诊断问题。选择发出警告消息是 C 实现的选择和质量问题,而不是 C 标准的规则。int x = x;
x
Apple Clang 11.0 即使使用 .我怀疑这是一个错误(如果不是偏离 C 标准的规则,也偏离了作者想要的),但也许有一些原因。int x = x;
-Wuninitialized -Winit-self
考虑如下代码:
int FirstIteration = 1;
int x;
for (int i = 0; i < N; ++i)
{
if (FirstIteration)
x = 4;
x = foo(x);
FirstIteration = 0;
}
编译器可能会观察到 在 中,因此可能未在 中初始化的原因。编译器可能被设计为在这种情况下发出警告消息,并且无法推断使用在 中使用之前始终初始化的保证。作为作者的断言,他们故意以这种方式设计代码,为他们提供了一种抑制虚假警告的方法。x = 4;
if
x
foo(x)
FirstIteration
x
foo(x)
int x = x;
脚注
1 有几个成语用来告诉编译者作者故意使用一些结构,这通常是一个错误。例如,是完全定义的 C 代码,它设置为 3 并且始终计算为 true,但这通常是一个预期的错误。该代码在 C 语义中是相同的,但额外括号的存在是用于表示“我故意使用赋值”的惯用语,因此编译器可能会警告 for ,但不会警告 .if (x = 3) …
x
if
x == 3
if ((x = 3)) …
if (x = 3) …
if ((x = 3)) …
评论
int x /* x exists now though it hasn't been assigned a value yet */ = x /* UB: using garbage value (should work "sanely" on any current computer) for initialization */;