代码:
int main(void)
{
auto a=1;
return 0;
}
文件扩展名为.c时,MS Visual Studio 2012编译器将编译该文件而不会出现错误。我一直认为,当您使用.c扩展名时,应根据C语法而不是C ++进行编译。而且,据我所知,自C ++ 11起,只有在C ++中才允许不带类型的auto ,这意味着从初始化程序推导出类型。
这是否意味着我的编译器不坚持使用C,或者代码在C语言中实际上是正确的吗?
代码:
int main(void)
{
auto a=1;
return 0;
}
文件扩展名为.c时,MS Visual Studio 2012编译器将编译该文件而不会出现错误。我一直认为,当您使用.c扩展名时,应根据C语法而不是C ++进行编译。而且,据我所知,自C ++ 11起,只有在C ++中才允许不带类型的auto ,这意味着从初始化程序推导出类型。
这是否意味着我的编译器不坚持使用C,或者代码在C语言中实际上是正确的吗?
Answers:
auto
是一个旧的C关键字,表示“本地范围”。auto a
与相同auto int a
,并且因为局部作用域是函数内部声明的变量的默认范围,所以它也与int a
此示例相同。
这个关键字实际上是C的前身B(没有基类型)的剩余部分:所有内容都是int
,指向。(*)的int
数组的指针,int
声明为auto
or或extrn
[sic]。C继承了“ everything is int
”作为默认规则,因此您可以使用
auto a;
extern b;
static c;
ISO C摆脱了这一点,但是许多编译器仍然接受它以实现向后兼容性。如果您不熟悉,那么您应该意识到相关规则正在实施中
unsigned d; // actually unsigned int
在现代代码中仍然很常见。
C ++ 11重用了该关键字以进行类型推断,该关键字很少(如果有的话,C ++程序员使用的是原始含义)。这是最安全的,因为int
在C ++ 98中已经删除了C 的“一切都是”规则。唯一中断的是auto T a
,无论如何都没有人使用过。(在他关于语言历史的论文中的某个地方,Stroustrup对此发表了评论,但我现在找不到确切的参考。)
(*)B中的字符串处理很有趣:您将使用数组int
并在每个成员中打包多个字符。B实际上是具有不同语法的BCPL。
-Werror
。
这既是答案,又是对No的扩展注释。自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”规则。该规则将强制编译器进行解释,auto a=1
就像auto int a=1
在C90或K&R模式下使用编译器时一样。
大多数编译器通常会拒绝包含非法语法的代码(拒绝:拒绝生成目标文件或可执行文件)。在这种情况下,编译器作者认为无法编译不是最佳选择。最好的办法是发出诊断信息,修复代码,然后继续进行。太多的遗留代码充斥着诸如之类的结构register a=1;
。编译器应该能够在C99或C11模式下编译该代码(当然带有诊断程序)。
-ffs-please-stop-allowing-constructs-from-some-previous-millennium
编译器选项,或更简洁地说是一个-fstrict-compliance
选项。抱怨编译器:“当我使用-std = c11时,我没想到可以编译古老的K&R kruft。实际上,我希望它不被编译!”
-std=c99
更加严格将是朝正确方向迈出的一步:)
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
和其他一些人可能是有用的,但是这是开始设置选项好。
-pedantic-errors
auto
具有2011年标准之内C
和C++
之前的含义。这意味着变量具有自动生存期,也就是由范围决定的生存期。这与例如static
生命周期相反,在生命周期中,变量会“永远”持续,而不管作用域如何。auto
是默认生存期,几乎永远不会明确指出。这就是为什么可以安全地更改中的含义的原因C++
。
现在C
,在99标准之前,如果您不指定变量的类型,则默认为int
。
因此,auto a = 1;
您要声明(并定义)一个int
变量,其生存期由范围决定。
(“寿命”更恰当地称为“存储期限”,但我认为可能不太清楚)。
main
功能范围的持续时间”。
auto
,并static
是只有两种可能性。我试图以针对发问者的方式来写我的答案,发问者对于C++
(和C
)似乎还很陌生,所以我稍微详细介绍了一下。也许那是个坏主意;他们迟早需要掩盖。
int
自1999
在C和C ++的历史方言中,auto
是a
具有自动存储功能的关键字。由于只能将其应用于默认情况下为自动的局部变量,因此没有人使用它。这就是C ++现在重新使用关键字的原因。
从历史上看,C允许没有类型说明符的变量声明。类型默认为int
。所以这个声明相当于
int a=1;
我认为这在现代C语言中已被弃用(并可能被禁止)。但是有些流行的编译器默认使用C90(我认为确实允许),并且令人讨厌的是,仅在您明确要求时才启用警告。用gcc编译并且用指定C99 -std=c99
,或使警告用-Wall
或-Wimplicit-int
,给出警告:
warning: type defaults to ‘int’ in declaration of ‘a’
在C中,auto
意味着register
在C ++ 11中做同样的事情:这意味着变量具有自动存储持续时间。
并且在C99之前的C中(并且Microsoft的编译器不支持C99或C11,尽管它可能支持它的一部分),但在许多情况下可以省略该类型,默认情况下为int
。
它根本不采用初始化程序的类型。您刚巧选择了一个兼容的初始化程序。
auto
并且register
具有完全相同的含义(我之前评论说,使用register
-qualified变量的地址有限制,但是对于C ++是不正确的)。register
虽然已弃用,但现在仍保留其旧含义。
auto
在C中的含义与register
在C ++中的含义相同(均表示自动存储持续时间,而没有其他含义)。
存储类定义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;
}
int
已于1999