Odd C сообщение об ошибке объявления глобального типа char как в G CC, так и в Clang? - PullRequest
0 голосов
/ 06 августа 2020

Вопрос: Это я, или G CC и Clang имеют не совсем правильные сообщения об ошибках при оценке конкретных глобальных объявлений char в C?

--- И особое примечание относительно Аналогичный вопрос заключается в том, что я ищу разъяснения относительно того, почему объявление char вызывает такую ​​реакцию. Да, есть связанные вопросы, но все, что я видел, это объявления int.

$ g cc --version g cc (Ubuntu 9.3.0-10ubuntu2) 9.3.0

$ clang --version clang version 10.0.0-4ubuntu1

Рассмотрим следующий C код, в состоянии. c:

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

Первое замечание: да, объединение объявление и инициализация способности намного эффективнее. Однако при запуске через G CC и 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 --- действительно здесь. Когда сообщения объявления и инициализации объединяются в этом месте, над / перед основной функцией, программа компилируется. Когда пара сообщений помещается в основную функцию, даже без объединения, программа также компилируется.

Итак, оператор charable; вполне подходит, так почему же эти сообщения об ошибках?

Ответы [ 4 ]

1 голос
/ 06 августа 2020

Вы не можете сделать

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]

Как вы можете видеть здесь, в грамматике, в базе translationunit нет места только для присваивания.

0 голосов
/ 06 августа 2020
 able = 'X';

У вас не может быть кода или назначений вне функций. компилятор рассматривает его как новые определения с неявным типом int. Присвоение должно быть в теле функции, как в примере.

#include <stdio.h>
char able;

void foo()
{
    able = 'X'; 
}

int main(void)
{
    foo();
    printf("%c", able);
}

https://godbolt.org/z/dea7q7

0 голосов
/ 06 августа 2020

Компиляция выдает ошибку, поскольку able='X' никогда не выполняется программой. (C программа действует последовательно только внутри функций. Для глобальных переменных рассматривается только объявление с / без инициализации.

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

Аналогичный вопрос можно найти по адресу: Почему я не могу присвоить значения глобальным переменным вне функции в C?

0 голосов
/ 06 августа 2020

Поскольку операторы не разрешены в области файла, компилятор пытается интерпретировать этот оператор

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 Блок позволяет сгруппировать набор объявлений и операторов в одну синтаксическую c единицу.

...