问题:是我,还是GCC和Clang在评估C中的特定全局字符声明时都没有完全正确的错误消息?
---关于一个类似的问题,有一个特别的注意点是,我希望澄清为什么char声明会得到这种反应。是的,有一些相关的问题,但我看到的只是int声明。
$gcc--版本gcc(Ubuntu 9.3.0-10ubuntu2(9.3.0
$clang--版本clang版本10.0.0.4ubuntu1
考虑以下C代码,表.C:
#include <stdio.h>
char able;
able = 'X';
int main(void)
{
printf("%c", able);
}
首先要注意的是,是的,将able的声明和初始化结合起来要有效得多。然而,当运行GCC和Clang时,在我看来,出现的错误消息基本上是不正确的消息:
$ clang -Weverything able.c
able.c:5:1: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
able = 'X';
^
able.c:5:1: error: redefinition of 'able' with a different type: 'int' vs 'char'
able.c:3:6: note: previous definition is here
char able;
^
able.c:3:6: warning: no previous extern declaration for non-static variable 'able' [-Wmissing-variable-declarations]
char able;
^
able.c:3:1: note: declare 'static' if the variable is not intended to be used outside of this translation unit
char able;
^
2 warnings and 1 error generated.
$ gcc -Wall -Wextra -Wpedantic able.c
able.c:5:1: warning: data definition has no type or storage class
5 | able = 'X';
| ^~~~
able.c:5:1: warning: type defaults to ‘int’ in declaration of ‘able’ [-Wimplicit-int]
able.c:5:1: error: conflicting types for ‘able’
able.c:3:6: note: previous declaration of ‘able’ was here
3 | char able;
| ^~~~
这两组消息都抱怨缺少类型说明符,只是类型说明符--char确实就在那里。当声明和初始化消息在主函数上方/之前的那个位置组合时,程序就会编译。当这对消息被放置在主函数中时,即使没有组合,程序也会编译。
因此字符语句非常好,那么为什么会出现这些错误消息呢?
你不能做
char able;
able='X';
在文件范围上。
您只能在一行中执行,而不能像在函数中使用的那样进行拆分。C编译器认为:
char able; //Declare a variable of type char with name able.
able = 'X'; //Assign the ASCII-value of 'X' to a variable called able of type `int`.
int是隐式的,因为它与真正旧的版本向后兼容。(因此,您有时会看到main()
而不是int main(void)
(。
此外,您现在有两个同名的变量。这导致了这个错误:
redefinition of 'able' with a different type: 'int' vs 'char'
编辑:
以下是C规范(草案(的摘录:附录A,A.1(词汇语法(,A.2.4(外部定义(
translation-unit: //Essentially a file
external-declaration
translation-unit external-declaration
external-declaration:
function-definition
declaration //The interesting one
declaration: //A 2.2 (Declarations)
declaration-specifiers init-declarator-list[opt];//init-declarator-list is optional
static_assert-declaration//Not interesting here
declaration-specifiers:
storage-class-specifier declaration-specifiers[opt]
type-specifier declaration-specifiers[opt]
type-qualifier declaration-specifiersopt
function-specifier declaration-specifiers[opt]
alignment-specifier declaration-specifiers[opt]
正如你在语法中看到的那样,在翻译单元的基础上没有只放作业的位置。
由于程序从未执行able='X'
,因此编译会出错。(C程序只在函数内部按顺序运行。对于全局变量,只考虑带/不带初始化的声明。
#include <stdio.h>
char able;
able = 'X'; //This statement is never executed
int main(void)
{
printf("%c", able);
}
类似的问题可以在中找到:为什么我不能为C中函数外的全局变量赋值?
由于不允许在文件范围内使用语句,编译器试图解释此语句
able = 'X';
作为声明。但它找不到类型说明符。所以它发出消息
able.c:5:1: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
able = 'X';
在插入默认类型说明符int
之后,它看到名称able
像一样声明了两次
char able;
int able = 'X';
其中int
是编译器默认插入的类型说明符。
因此编译器发出消息
able.c:5:1: error: redefinition of 'able' with a different type: 'int' vs 'char'
able.c:3:6: note: previous definition is here
char able;
^
在块范围内,您可以放置声明和语句。所以这个代码片段
char able;
able = 'X';
放置在函数块作用域中将成功编译。
来自C标准(6.8语句和块(
3块允许对一组声明和语句进行分组成为一个句法单元。
able = 'X';
函数之外不能有任何代码或赋值。编译器将其视为具有隐式int
类型的新定义。赋值必须在函数体中,如示例所示。
#include <stdio.h>
char able;
void foo()
{
able = 'X';
}
int main(void)
{
foo();
printf("%c", able);
}
https://godbolt.org/z/dea7q7