代码:
int main(void)
{
auto a=1;
return 0;
}
当文件扩展名为.c时,使用MS Visual Studio 2012编译器可以无错误编译。我一直认为如果使用.c扩展名,则应根据C语法而不是C++进行编译。此外,据我所知,自C++11以来,只有在C++中允许使用没有类型的auto,其中它表示类型是从初始化程序推断出来的。
那是否意味着我的编译器没有遵循C语言,还是代码实际上在C语言中是正确的?
auto
是一个旧的C关键字,意思是“局部作用域”。auto a
与auto int a
相同,并且因为在函数内声明变量时,局部作用域是默认的,所以在这个例子中它也与int a
相同。int
、指向int
的指针、int
数组。声明可以是auto
或extrn
[sic]。C继承了“一切都是int
”作为默认规则,因此您可以使用auto
声明整数。auto a;
extern b;
static c;
unsigned d; // actually unsigned int
这种用法在现代编程中仍然很常见。
C++11重复使用了这个关键字,但几乎没有C ++程序员在使用原始含义,而是用于类型推断。这基本上是安全的,因为从C中删除了“一切都是int
”规则已经在C ++ 98中实现;唯一的问题是auto T a
,但是任何人都不会使用它。(Stroustrup在他的papers on the history of the language中的某个地方对此发表了评论,但我现在找不到确切的参考文献。)
(*) B中的字符串处理很有趣:您将使用int
数组,并在每个成员中打包多个字符。实际上,B是具有不同语法的BCPL。
这既是一个答案,也是对“不,自1999年以来这不是合法的C。没有一个像样的现代C编译器允许这样做。”的延伸评论。
是的,auto a=1;
在C1999(和C2011)中是不合法的。仅仅因为现在已经不合法了,并不意味着现代C编译器应该拒绝包含这种构造的代码。我会争辩恰好相反,即一个像样的现代C编译器必须仍然允许这一点。
当编译问题中的示例代码时,无论是针对1999版本还是2011版本的标准,clang和gcc都会发出诊断,然后继续执行,就好像被反对的语句是auto int a=1;
。
在我看来,这就是一个像样的编译器应该做的事情。通过发出诊断信息,clang和gcc完全符合标准。标准并没有说一个编译器必须拒绝非法代码。标准只是说,如果翻译单元包含任何语法规则或约束的违规行为,符合规范的实现必须产生至少一个诊断消息(5.1.1.3)。
给定包含非法构造的代码,任何像样的编译器都会尝试理解非法的代码,以便编译器可以找到代码中的下一个错误。一个在第一个错误处停止的编译器不是一个很好的编译器。有一种方法可以从auto a=1
中获得意义,那就是应用“隐式int”规则。当编译器在C90或K&R模式下使用时,此规则强制编译器将auto a=1
解释为auto int a=1
。
大多数编译器通常会拒绝包含非法语法的代码(即拒绝生成目标文件或可执行文件)。这是编译器作者认为不能编译的情况之一。最好的做法是发出诊断,修复代码,并继续进行。只是太多的遗留代码中充斥着如register a=1;
这样的构造。编译器应该能够在C99或C11模式下编译该代码(当然还要发出诊断)。
gcc -g -O3 -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror
(这是我通常使用的,即使是从SO上的问题代码),那么你会得到接近你想要的结果。我希望GCC默认至少为 -std=c99
,最好是 -std=c11
(或者 -std=gnu11
;他们更可能这样做),但在此之前,... 你可以调整这些选项;-pedantic
、-Wshadow
、-Wold-style-declaration
和其他一些选项可能很有用,但这是一个很好的起点选项集。 - Jonathan Lefflerauto
在2011年之前的C
和C++
中有一个含义。它表示变量具有自动存储期,即由范围确定的存储期。这与例如static
存储期相对,后者表示变量将“永久”存在,无论范围如何。 auto
是默认存储期,几乎从不显式地拼写出来。这就是为什么在C++
中更改其含义是安全的原因。
现在,在99标准之前的C
中,如果没有指定变量的类型,则默认为int
。
所以,使用auto a = 1;
声明(和定义)了一个int
变量,并且其存储期由范围确定。
(“存储期”更准确地称为“存储持续时间”,但我认为这可能不太清晰)。
auto
和 static
是仅有的两种可能性。我试图以针对提问者的方式来回答问题,他似乎对 C++
(和 C
)还很陌生,所以我略微忽略了一些细节。也许这是个坏主意;这些内容迟早需要被涵盖到。 - BoBTFishint
已经被移除。 - Jens Gustedtauto
是一个关键字,意味着a
具有自动存储。由于它只能应用于默认为自动的本地变量,因此没有人使用它;这就是为什么C++现在重新定义了该关键字的原因。int
。因此,这个声明等同于:int a=1;
我认为这在现代C语言中已经被废弃(并且可能是被禁止的);但一些流行的编译器默认使用C90(我认为是允许的),令人恼火的是,只有在你明确要求时才会启用警告。使用GCC编译并指定C99选项-std=c99
或启用警告-Wall
或-Wimplicit-int
时,会给出一个警告:
warning: type defaults to ‘int’ in declaration of ‘a’
auto
的意思和在C++11中register
是一样的:它表示变量具有自动存储期。在C99之前的C语言(Microsoft的编译器不支持C99或C11,尽管它可能支持其中的一些部分),在许多情况下可以省略类型,其中默认为int
。它根本不从初始化程序获取类型。你只是碰巧选择了一个兼容的初始化程序。auto
和 register
具有完全相同的含义(我之前评论过一个 register
-qualified 变量地址限制的问题,但这对于 C++ 是不正确的)。虽然 register
已被弃用,但现在仍保留其旧的含义。 - user743382auto
和在C++中的 register
意思相同,这是正确的(两者都表示自动存储期限,并且没有其他含义)。 - Mike Seymour存储类定义了C程序中变量和/或函数的作用域(可见性)和生命周期。
以下是C程序中可以使用的存储类:
auto
register
static
extern
auto
是所有局部变量的默认存储类。
{
int Count;
auto int Month;
}
上面的示例定义了两个具有相同存储类的变量。auto只能在函数内部使用,即局部变量。
int
是下面代码中auto
的默认类型:
auto Month;
/* Equals to */
int Month;
/* Default-int */
main()
{
reurn 0;
}
Visual Studio编译类型可在右键单击文件 -> 属性 -> C/C++ -> 高级 -> 编译为
中找到。为确保强制编译为C,请使用/TC
选项。在这种情况下,它是larsmans所说的(旧的C auto
关键字)。否则可能会在您不知道的情况下编译为C++。
int
已于1999年从C标准中删除。 - Jens Gustedt