【问题标题】:Odd C global char type declaration error message in both GCC and Clang?GCC 和 Clang 中的奇数 C 全局字符类型声明错误消息?
【发布时间】:2020-11-26 14:54:35
【问题描述】:

问题:是我,还是 GCC 和 Clang 在评估 C 中的特定全局 char 声明时都没有完全正确的错误消息?

---关于类似问题的一个特别说明是,我正在寻找关于为什么 char 声明会得到这种反应的说明。有相关的问题,是的,但我看到的都是 int 声明。

$ gcc --version gcc (Ubuntu 9.3.0-10ubuntu2) 9.3.0

$ clang --version clang 版本 10.0.0-4ubuntu1

考虑以下 C 代码,able.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---确实在那里。当声明和初始化消息在该位置组合时,在主函数上方/之前,程序编译。当这对消息放在main函数中时,即使不合并,程序也可以编译。

所以 charable; 语句完全没问题,那为什么会出现这些错误消息?

【问题讨论】:

  • 请正确格式化您的代码
  • 这在 C 中并不奇怪。全局变量,即出现在函数之外的任何变量只能在初始化时被赋予初始值。它不能用函数外的其他值重新定义,但是,在任何函数内部,我们都可以改变它的值。

标签: c gcc char clang global


【解决方案1】:

你做不到

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 specification (Draft) 的摘录: 附录 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]

正如您在语法中看到的那样,translationunit-base 上没有位置仅用于分配。

【讨论】:

    【解决方案2】:

    编译会出错,因为程序永远不会执行able='X'。 (C 程序仅在函数内部按顺序执行。对于全局变量,仅考虑带/不带初始化的声明。

    #include <stdio.h>
    char able;
    able = 'X';    //This statement is never executed
    int main(void)
    {
        printf("%c", able);
    }
    

    可以在以下位置找到类似的问题:Why can't I assign values to global variables outside a function in C?

    【讨论】:

      【解决方案3】:

      由于文件范围内不允许使用语句,因此编译器会尝试解释该语句

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

      在块作用域内你可以放置声明和语句。所以这段代码sn -p

      char able;
      able = 'X';
      

      放置在功能块范围内会编译成功。

      来自 C 标准(6.8 语句和块)

      3 块允许对一组声明和语句进行分组 成一个句法单元。

      【讨论】:

        【解决方案4】:
         able = 'X';
        

        你不能在函数之外有任何代码或赋值。编译器将其视为具有隐式 int 类型的新定义。赋值必须在函数体中,如示例所示。

        #include <stdio.h>
        char able;
        
        void foo()
        {
            able = 'X'; 
        }
        
        int main(void)
        {
            foo();
            printf("%c", able);
        }
        

        https://godbolt.org/z/dea7q7

        【讨论】:

          猜你喜欢
          • 2019-12-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-11-16
          • 2019-04-02
          • 2011-05-30
          • 2020-08-03
          • 2021-11-22
          相关资源
          最近更新 更多