为什么auto a = 1; 用C编译?

lee*_*e77 125 c auto c11

代码:

int main(void)
{
    auto a=1;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

当文件具有.c扩展名时,MS Visual Studio 2012编译器会编译无错误.我一直认为,当你使用.c扩展名时,编译应该是根据C语法,而不是C++.而且,据我所知,自C++ 11以来允许在C++中使用auto类型,这意味着该类型是从初始化程序推导出来的.

这是否意味着我的编译器不坚持C,或者C语言中的代码实际上是否正确?

Fre*_*Foo 240

auto是一个旧的C关键字,意思是"本地范围".auto a与此函数相同auto int a,并且因为局部作用域是函数内声明的变量的默认值,所以它也与int a此示例中的相同.

这个关键字实际上是C的前身B的剩余部分,其中没有基类型:一切都是int,指针int,数组int.(*)声明将是auto或者extrn[sic].C继承了"一切都是int"作为默认规则,因此您可以使用声明整数

auto a;
extern b;
static c;
Run Code Online (Sandbox Code Playgroud)

ISO C摆脱了这一点,但许多编译器仍然接受它以实现向后兼容.如果它似乎不熟悉,那么你应该意识到一个相关的规则正在发挥作用

unsigned d;  // actually unsigned int
Run Code Online (Sandbox Code Playgroud)

这在现代代码中仍然很常见.

C++ 11重用了关键字,这个关键字很少,如果有任何C++程序员使用它的原始含义,它的类型推断.这大多是安全的,因为intC中的"一切都是"规则已经在C++ 98中被删除了; 唯一打破的是auto T a,无论如何都没有人使用.(在他关于语言历史的论文中,Stroustrup对此进行了评论,但我现在找不到确切的参考.)

(*)B中的字符串处理很有意思:你int在每个成员中使用数组并包含多个字符.B实际上是BCPL,语法不同.

  • @JensGustedt - re*不,自1999年以来这不是合法的C.没有像样的现代C编译器允许这样做.*第一个陈述是正确的; 这是自1999年以来的违法行为.恕我直言,第二个陈述是不正确的.任何体面的现代C编译器都必须允许这样做.查看在不允许的情况下必须重写的所有遗留代码.我写了一个答案,扩展了这个评论. (40认同)
  • @JensGustedt:你确定吗?GCC和Clang都在C99模式下对它进行了警告,但除了`-Werror`之外,他们并不认为这是一个错误. (23认同)
  • @JensGustedt VS并未声称提供现代C编译器.从各方面来看,C编译器的工作在很多年前停止了; 他们只提供它,以便人们可以继续编译遗留代码.(当然,任何体面的现代C编译器都可以选择支持遗留代码.包括K&R C的选项.) (18认同)
  • 不,自1999年以来,这不是合法的C.没有像样的现代C编译器允许这样做. (7认同)
  • @larsman,是的,在6.7.2中有一个明确的约束条件:*每个声明中的声明说明符中至少应给出一个类型说明符......* (2认同)

Dav*_*men 35

这既是答案又是对No的扩展评论,自1999年以来这不是合法的C.没有像样的现代C编译器允许这样做.

是的,auto a=1;在C1999(以及C2011)中是非法的.仅仅因为这现在是非法的并不意味着现代C编译器应该拒绝包含这种结构的代码.我认为恰恰相反,一个体面的现代C编译器仍然必须允许这样做.

clang和gcc都是在根据1999或2011版本的标准编译问题中的示例代码时做的.两个编译器都发出诊断信息,然后继续进行,就好像有令人反感的陈述一样auto int a=1;.

在我看来,这是一个体面的编译器应该做的事情.通过发布诊断,clang和gcc完全符合标准.该标准并未说明编译器必须拒绝非法代码.该标准仅表示如果翻译单元包含违反任何语法规则或约束(5.1.1.3),则符合实现必须至少生成一条诊断消息.

给定包含非法构造的代码,任何体面的编译器都会尝试理解非法代码,以便编译器可以在代码中找到下一个错误.在第一个错误处停止的编译器不是一个非常好的编译器.有一种方法可以理解auto a=1,即应用"隐式整数"规则.此规则强制编译器解释auto a=1auto int a=1在C90或K&R模式下使用编译器时的情况.

大多数编译器通常拒绝包含非法语法的代码(拒绝:拒绝生成目标文件或可执行文件).在这种情况下,编译器作者认为无法编译不是最佳选择.最好的办法是发布诊断,修复代码,然后继续.有太多遗留代码,其中包含诸如此类的构造register a=1;.编译器应该能够以C99或C11模式编译该代码(当然还有诊断).

  • @DavidHammen:圈复杂度,项目经理和公司政策都不是语言的要素. (3认同)
  • 在GCC中获得所需行为的标志是`-pedantic-errors` (3认同)

BoB*_*ish 29

auto具有2011标准之前CC++之前的含义.这意味着变量具有自动生命周期,即由范围确定的生命周期.这与例如static寿命相反,其中变量持续"永久",而不管范围如何.auto是默认生命周期,几乎从未明确拼写过.这就是为什么改变其含义是安全的C++.

现在C,在99 Standard之前,如果您没有指定变量的类型,则默认为int.

因此,auto a = 1;您将声明(并定义)一个int变量,其寿命由范围决定.

("生命周期"更恰当地称为"存储持续时间",但我认为这可能不太清楚).


Mik*_*our 8

在C和C++的历史方言中,auto关键字意味着a具有自动存储.因为它只能应用于默认情况下自动的局部变量,所以没有人使用它; 这就是为什么C++现在改变了关键字的用途.

从历史上看,C允许变量声明没有类型说明符; 类型默认为int.所以这个宣言相当于

int a=1;
Run Code Online (Sandbox Code Playgroud)

我认为这在现代C中被弃用(并且可能被禁止); 但是一些流行的编译器默认使用C90(我认为它确实允许它),并且,令人讨厌的是,如果您特别要求它们,则仅启用警告.用gcc编译并且用指定C99 -std=c99,或使警告用-Wall-Wimplicit-int,给出警告:

warning: type defaults to ‘int’ in declaration of ‘a’
Run Code Online (Sandbox Code Playgroud)

  • 自1999年以来,它确实被禁止进入. (4认同)

小智 5

在C中,auto意味着register在C++ 11中也是如此:它意味着变量具有自动存储持续时间.

在C99之前的C中(并且Microsoft的编译器不支持C99或C11,虽然它可能支持它的一部分),但在许多情况下它可以省略,默认情况下int.

它根本不采用初始化器的类型.你碰巧选择了兼容的初始化程序.

  • @JensGustedt:答案并不是说他们是.它说C中的`auto`与C++中的`register`相同,它就是这样(两者都意味着自动存储持续时间,没有别的). (5认同)