【问题标题】:C89 and variable initializationC89 和变量初始化
【发布时间】:2015-12-23 13:16:28
【问题描述】:

C89 (C90, ANSI-C) 不允许将变量声明与代码混合。我想知道变量初始化在多大程度上被认为是“代码”。

也许只有用常量表达式初始化才有效?

具体来说,如果我正在编写 C 代码并且我想安全起见(最大化与 ANSI-C 编译器的兼容性),是否应该认为以下内容是安全的?

  void f1(void) { 
      int x = 30;
      int y = 40;
      int z;
      /* ... */
  }

  void f2(void) { 
      int x = 30, y = 40;
      int z;
      /* ... */
  }

  #define MYCONST (90)
  void f3(void) { 
      int x = 3; 
      int y = 4 + MYCONST;
      int z;
      /* ... */
  }

  void f4(void) { 
      int x = 3;
      int y = time(NULL);
      int z = 10 + x;
      /* ... */
  }

【问题讨论】:

  • ANSI-C 不是也更新到 C99 了吗?
  • @user3528438 ANSI-C 是指由 ANSI 发布的唯一规范,即 C89。 C90 是 ISO 次年采用的 C89,所有后续更新(C99 和 C11)都是 ISO C。
  • 就目前而言,您的代码无法编译。您的意思是在函数f3f4 中的第一个声明之后放置分号而不是逗号?
  • @PCLuddite 是的,当然。已修复 - 谢谢
  • @Olaf: user3528438几乎正确; ANSI 采用了 ISO C11,就 ISO 和 ANSI 而言,C99 已正式过时。 (但短语“ANSI C”通常指的是 C89/C90——这就是为什么我尽量避免使用该特定术语。)

标签: c c89 ansi-c


【解决方案1】:

以下是否应该被认为是安全的?

您发布的所有代码都是安全的。

  1. 您可以在任何范围内拥有任意数量的变量声明。
  2. 初始化变量的代码可以使用该语言提供的任何方法。

但是,在非变量声明的代码之后声明变量是不合法的。

void foo()
{
   int i = 0;
   i = 2;      // Does not declare a variable.
   int j = 10; // Not legal.
}

以上代码适用于 gcc。但是,如果您使用 -pedantic 标志,您将看到一条类似于以下内容的警告消息:

soc.c:5:4: warning: ISO C90 forbids mixed declarations and code [-Wpedantic]
    int j = 10;

【讨论】:

  • 您是否混淆了声明定义
  • 这个答案的开头部分是题外话。这个问题没有问到它。
  • @Olaf,不,我没有混淆声明和定义。如果将 int j = 10; 替换为 extern int j;,您将看到相同的警告。
  • @PCLuddite,我的示例函数的目的是演示非法代码,与 OP 示例中的合法代码形成对比。
  • @RSahu 我建议把你的最后两句话放在前面:“初始化变量的代码可以使用语言提供的任何方法。你所有的例子都很好。” 然后你可以进入对比不合法的地方。照原样,开始阅读答案时的第一印象是“这甚至不是问题的内容?这个答案甚至理解了这个问题吗?”
【解决方案2】:

C89 不允许在同一范围内混合声明和语句。我们在这里指的是函数内部的声明和语句,因为在 C 中不允许在函数外部使用语句。

int a = foo(a, b);  /* declared at block-scope */

上面的行是一个(有效的 C89)声明,而不是一个声明,因此您的所有函数 f1、f2、f3 和 f4 都是有效的 C89。

但是,您可以在不同的范围内混合声明和语句:

void bar(void)
{
    int i = 0;  /* declaration */
    i++;  /* statement */
    {
        int j = 0;  /* declaration */
        j++;  /* statement */
     }
 }

上面的函数是C89有效的。

【讨论】:

    【解决方案3】:

    C99 标准本身的前言提到“混合声明和代码”是对 C90 的更改之一。恕我直言,这是一个糟糕的词选择,因为根本不清楚“代码”的含义。它可以轻松引用 C 源文件中可能出现的所有内容。

    C99 所做的实际更改是允许在一个块中混合声明和语句declarationstatement 之间的区别由语言语法明确定义。

    你的例子之一:

    int y = time(NULL);
    

    是声明,而不是语句,即使它导致在运行时执行某些代码。初始值设定项的存在与否,以及该初始值设定项是否为常量表达式,都不会影响某事物是否被视为声明。

    您问题中的所有四个示例在 C89/C90、C99 和 C11 中均有效。在每种情况下,块都只包含声明,没有语句。

    如果你想在 C90 中混合声明和语句,你可以通过引入嵌套块来实现:

    void func(void) {
        int x = 1; /* a declaration */
        x = 2;     /* a statement; no declarations may follow in C90 */
        {
            int y = 3; /* a declaration */
            y = 4;     /* a statement */
        }
    }
    

    内部块本身就是一个语句。因为它是一个声明,所以它可以出现在那个上下文中。因为它是一个复合语句,它本身可以包含一系列声明,后跟一系列语句。

    即使在 C99 或 C11 中,引入这样的嵌套块也是有利的。 y 的范围和生命周期在包含其声明的块的结束 } 处结束。限制声明的范围可以使代码更容易理解。

    (一点背景知识:C89 是 ANSI 于 1989 年发布的标准。ISO 采用了它,但在文档中进行了一些更改,但在其描述的语言上没有作为 C90。ISO 发布了更新的标准 C99,它是然后被 ISO 采用。ISO 发布了另一个更新的标准 C11,也被 ANSI 采用。根据 ANSI 和 ISO,2011 标准是当前标准,所有早期版本都已过时。但由于历史原因,短语“ ANSI C”通常指的是 1989 年和 1990 年版本所描述的语言。我通常会尽量避免使用“ANSI C”这个短语,而是指“ISO C”,如果相关,还可以加上出版年份。)

    【讨论】:

      【解决方案4】:

      您的所有示例都是合法的,可以安全地与符合 ANSI-C 的编译器一起使用。

      使用-std=c89-pedanticgcc 中编译您的代码不会产生任何警告。

      【讨论】:

        【解决方案5】:

        使用以下代码进一步观察 C89/99 版本差异:
        (对 C 标准的 C99 扩展似乎对可以放置额外声明的位置不再那么迂腐了)

        int main() 
        { 
            int a; //declaration only
            int b; //declaration only
            b = 5; //assignment only (no declaration)
            int c; //declaration only  (fails C89, Compiles C99)
        
            return 0; 
        }
        

        下图说明了使用 C89 设置并在 assignment 语句后尝试 declaration 时的错误。 (设置为使用C99时,代码编译无误)

        【讨论】:

        • "您的代码示例使用 C99 是完全安全的,但不使用 C89" 但是您的代码示例都不是我的代码示例...
        • @leonbloy - 您的帖子专门讨论了 C89 规则,即合规编译器在代码中的何处接受声明。我提供了这个只是作为该场景的一个更简化的轶事说明,即表明在块范围内,并且在进行赋值语句之后,将不允许后续声明。我后来提供这篇文章的原因是因为我的实际测试结果与至少一个其他帖子的陈述结论不一致,我觉得这很有趣。显然,并非所有 C89 编译器都是平等的。
        【解决方案6】:

        F1、f2、f3 有效,但 f4 无效,因为声明和定义混在一起

        【讨论】:

        • 这没有意义。他的所有功能都结合了声明和定义。为什么f4 很特别?
        猜你喜欢
        • 2021-07-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-02-19
        • 2021-06-21
        • 1970-01-01
        • 1970-01-01
        • 2019-05-17
        相关资源
        最近更新 更多