简体   繁体   English

C89 和变量初始化

[英]C89 and variable initialization

C89 (C90, ANSI-C) does not allow intermixing variables declaration with code. C89(C90、ANSI-C)不允许在代码中混用变量声明。 I wonder to what extent a variable initialization is considered "code".我想知道变量初始化在多大程度上被认为是“代码”。

Perhaps it's only valid to initialize with constant expressions?也许只有用常量表达式初始化才有效?

Specifically, if I'm writing C code and I want to play safe (maximize compatibility with ANSI-C compilers), should the following be considered safe?具体来说,如果我正在编写 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;
      /* ... */
  }

should the following be considered safe?应该认为以下是安全的吗?

All of your posted code is safe.您发布的所有代码都是安全的。

  1. You may have any number of variable declarations in any scope.您可以在任何范围内拥有任意数量的变量声明。
  2. The code to initialize the variables may use any method the language provides.初始化变量的代码可以使用语言提供的任何方法。

However, it is not legal to declare a variable after code that is not variable declaration.但是,在不是变量声明的代码之后声明变量是不合法的。

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

The above code works with gcc.上面的代码适用于 gcc。 However, if you use the -pedantic flag, you will see a warning message that will look something like:但是,如果您使用-pedantic标志,您将看到如下所示的警告消息:

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

C89 does not allows mixing declarations and statements in the same scope. C89 不允许在同一范围内混合声明和语句。 We are referring here to declarations and statements inside functions as statements are not allowed outside functions in C.我们在这里指的是函数内部的声明和语句,因为 C 中不允许在函数外部使用语句。

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

The line above is a (valid C89) declaration, not a statement so all your functions f1, f2, f3, and f4 are valid C89.上面的行是(有效的 C89)声明,而不是声明,因此您的所有函数 f1、f2、f3 和 f4 都是有效的 C89。

However you are allowed to mix declarations and statements in different scopes:但是,您可以在不同范围内混合声明和语句:

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

The function above is valid C89.以上功能对C89有效。

The Foreword to the C99 standard itself mentions "mixed declarations and code" as one of the changes from C90. C99 标准本身的前言提到“混合声明和代码”是 C90 的变化之一。 This was IMHO a poor choice of words, since it's not at all clear what "code" means.恕我直言,这是一个糟糕的词选择,因为根本不清楚“代码”的含义。 It can easily refer to everything that can appear in a C source file.它可以轻松引用可以出现在 C 源文件中的所有内容。

The actual change that was made by C99 was to permit mixing of declarations and statements within a block. C99 所做的实际更改是允许在块内混合声明和语句 The distinction between a declaration and a statement is unambiguously defined by the language syntax.声明语句之间的区别由语言语法明确定义。

The line from one of your examples:您的示例之一中的行:

int y = time(NULL);

is a declaration, not a statement, even though it results in the execution of some code at run time.是声明,而不是语句,即使它导致在运行时执行某些代码。 The presence or absence of an initializer, and whether that initializer is a constant expression or not, does not affect whether something is considered to be a declaration.初始化器的存在与否,以及该初始化器是否是一个常量表达式,并不影响某物是否被视为声明。

All four of the examples in your question are valid in C89/C90, in C99, and in C11.您问题中的所有四个示例在 C89/C90、C99 和 C11 中均有效。 In each case, the block contains just declarations, no statements.在每种情况下,块只包含声明,不包含语句。

If you want to mix declarations and statements in C90, you do so by introducing nested blocks:如果你想在 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 */
    }
}

The inner block it itself a statement.内部块本身就是一个语句。 Because it's a statement, it can appear in that context.因为它是一个陈述,所以它可以出现在那个上下文中。 Because it's a compound statement, it can itself contain a sequence of declarations followed by a sequence of statements.因为它是一个复合语句,它本身可以包含一系列声明,然后是一系列语句。

Even in C99 or C11, it can be advantageous to introduce nested blocks like this.即使在 C99 或 C11 中,引入这样的嵌套块也是有利的。 The scope and lifetime of y end at the closing } of the block that contains its declaration. y的范围和生命周期在包含其声明的块的结束}处结束。 Restricting the scope of a declaration can make code easier to understand.限制声明的范围可以使代码更容易理解。

(A bit of background: C89 was the standard released by ANSI in 1989. ISO adopted it, with some changes in the document but not in the language it describes, as C90. ISO published an updated standard, C99, which was then adopted by ISO. ISO published another updated standard, C11, which was also adopted by ANSI. According to both ANSI and ISO, the 2011 standard is the current one, and all earlier editions are obsolete. But for historical reasons, the phrase "ANSI C" usually refers to the language described by the 1989 and 1990 editions. I usually try to avoid the phrase "ANSI C", referring instead to "ISO C", plus the publication year if it's relevant.) (一点背景知识:C89 是 ANSI 于 1989 年发布的标准。ISO 采用了它,在文档中做了一些更改,但没有对其描述的语言进行一些更改,如 C90。ISO 发布了更新的标准 C99,然后由ISO. ISO 发布了另一个更新的标准,C11,也被 ANSI 采用。根据 ANSI 和 ISO,2011 标准是当前标准,所有早期版本都已过时。但由于历史原因,短语“ANSI C”通常指的是 1989 和 1990 版所描述的语言。我通常会尽量避免使用“ANSI C”这一短语,而是指“ISO C”,如果相关,还要加上出版年份。)

All of your examples are legal and can safely be used with conforming ANSI-C compilers.您的所有示例都是合法的,并且可以安全地与符合 ANSI-C 的编译器一起使用。

Compiling your code in gcc with -std=c89 and -pedantic generates no warnings.使用-std=c89-pedanticgcc编译代码-pedantic产生警告。

An additional observation about C89/99 version differences using the following code:使用以下代码对 C89/99 版本差异进行额外观察:
(C99 extensions to the C standard appear to have become less pedantic on where additional declarations can be placed) (C99 对 C 标准的扩展似乎对可以放置附加声明的位置变得不那么迂腐了)

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; 
}

The following image illustrates errors when using C89 settings, and attempting a declaration after an assignment statement.下图说明了使用 C89 设置以及在赋值语句后尝试声明时的错误。 (When set to use C99, the code compiled without error) (设置为使用C99时,代码编译无误)

在此处输入图片说明

F1、f2、f3 有效但 f4 无效,因为声明和定义是混合的

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM