GCC 选项 -Wdeclaration-after-statement 是否纯粹是风格化的?

Is the GCC option -Wdeclaration-after-statement purely stylistic?

-Wdeclaration-after-statement 选项是否仅用于文体?我的意思是,如果我在我的 C 代码中定义了一个变量的所有情况都被宏化了,并且我以相同的方式在它们中初始化了它们,从这个旧样式的 C90 迁移到更新的 C99 样式,那么该代码是否是 byte-for -字节相同?

以下是选项 -Wdeclaration-after-statement 的记录方式(来自 man gcc):

Warn when a declaration is found after a statement in a block. This construct, known from C++, was introduced with ISO C99 and is by default allowed in GCC. It is not supported by ISO C90.

而且它允许你使用像

这样的代码
int a;
{
    a = 42;
    printf( "%d", a );
}

然后变成

int a = 42;
printf( "%d", a );

这是一个

不,不是。例如,上面的两个片段将逐字节编译相同。下面的foobar也会,baz不会。这里有一个link to GodBolt这表明将初始化提升到声明可能不会产生相同的代码

void foo () {
    int a;
    {
        if ( 1 ) {
            a = 42;
            printf( "%d", a );
        }
        else {
            a = 42;
            printf( "%d", a );
        }
    }
}

void bar () {
    int a = 42;
    {
        if ( 1 ) {
            printf( "%d", a );
        }
        else {
            printf( "%d", a );
        }
    }
}

void baz () {
    int a;
    {
        if ( rand() > 0 ) {
            a = 42;
            printf( "%d", a );
        }
        else {
            a = 42;
            printf( "%d", a );
        }
    }
}

我可能在这里感到困惑,但我认为我们遗漏了一些东西。

在 C99 之前,所有变量声明都必须在块中的任何语句之前出现。在何处为其赋值并不重要(可能在生成的汇编代码中除外)。

int a;
do_something();
a = 7;
do_something_else();

您在 C 中不能做但在 C++ 中一直完全合法的是混合声明和语句:

do_something();
int a = 7;
do_something_else();

随着 C99 的出现,您现在可以在 C 中执行与在 C++ 中相同的操作,并在块中的任何位置声明变量,即使是在非声明语句之后。

最终,这是一个基于使编写泄漏到语言规范中的编译器更容易的设计决策。编译器现在更复杂一些(而且更大)。

在此上下文中的语句要么指代以 ; 结尾的完整表达式,要么指代 复合语句 { }。这些术语取自正式的 C 语法。

声明after声明不适用于您问题中的代码。因为...您将声明 放在了 一个(复合)语句之前。您的两个示例与此 gcc 设置无关,因此您可能误解了它的作用。

相反,相关的例子是:

{
    int a = 42;
}

对比

{
  puts("hello");
  int a = 42;
}

前面的例子在任何 C 版本中都可以。后者适用于标准 C,但不适用于已弃用的 C90 标准。因此,现在警告的唯一目的是为强制执行某种编码风格的标准 C 程序提供诊断消息。

那里的绝大多数程序员不应使用此警告并坚持使用 ISO 9899:2018 中定义的标准 C。


编辑:

This is merely about whether or not you can rewrite code from a C90 to C99 conventions and obtain binary compatibility

是的,您可以重写为 C99 风格而不会产生任何后果。 None 其中影响变量在 C 调用的“抽象机”中的处理方式。以下是一些示例,2 个相关,1 个不相关:

void relevant_c99_example (void) {
    if ( 1 ) {
        int a = 42;
        printf( "%d", a );
    }
    else {
        int a = 42;
        printf( "%d", a );
    }
}

void relevant_c90_example (void) {
    int a = 42;
    if ( 1 ) {
        printf( "%d", a );
    }
    else {
        printf( "%d", a );
    }
}

void irrelevant_example (void) {
    int a;
    if ( 1 ) {
        a = 42;
        printf( "%d", a );
    }
    else {
        a = 42;
        printf( "%d", a );
    }
}

https://godbolt.org/z/1oqvoesx7

这 3 个在 x86_64 的 gcc clang 上测试时产生 100% 相同的机器代码。当禁用优化时,它们甚至会生成 100% 相同的机器代码!哪一个不应该期望,因为那不是您正确基准测试 C 代码的方式。但是这里恰好是这样。