5

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;
      /* ... */
  }
4

6 回答 6

4

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

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

  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;
于 2015-09-25T16:50:15.423 回答
2

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

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

您的一个示例中的行:

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 中,引入这样的嵌套块也是有利的。end 在包含其声明的块y结束时的范围和生命周期。}限制声明的范围可以使代码更容易理解。

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

于 2015-09-25T19:09:30.413 回答
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。

于 2015-09-25T18:19:50.683 回答
1

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

编译你的代码并且gcc不会产生任何警告。-std=c89-pedantic

于 2015-09-25T17:21:34.463 回答
0

使用以下代码对 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 设置并在赋值语句后尝试声明时出现的错误。(设置为使用C99时,代码编译无误)

在此处输入图像描述

于 2015-09-25T18:10:04.913 回答
-2

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

于 2015-09-25T17:04:35.843 回答