Является ли неявное преобразование указателя в _Bool недостатком компилятора?

В ответах на этот вопрос указано, что скаляры могут быть преобразованы в _Bool и что результирующее целочисленное значение _Bool будет 0 или 1.

Принятый ответ на этот вопрос указывает, что указатели являются скалярами.

Является ли ошибка неявного преобразования указателя в _Bool ошибкой компилятора?

E.g.:

$ cat ./main.c 
// main.c

#include <stdbool.h>

int main( int argc, char* argv )
{
  int  i;
  int* p   = &i;
  bool foo = (bool)p;
  bool bar = p;

  return 0;
}

Сбойный компилятор (один из одного):

$ /path/to/mips_fp_le-gcc --version
2.95.3
$ /path/to/mips_fp_le-gcc ./main.c 
./main.c: In function `main':
./main.c:10: incompatible types in initialization

Проходящий компилятор (один из многих):

$ gcc --version
gcc (GCC) 8.3.1 20190223 (Red Hat 8.3.1-2)
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ gcc ./main.c 
$ 

Обратите внимание, что только неявное преобразование, а не приведение (явное преобразование) помечается проблемным компилятором как ошибка.
Также обратите внимание, что согласно комментарию к этот вопрос, компилятор отмеченной проблемы старый - с 2001 года - это может иметь отношение к тому, является ли это подлинной ошибкой компилятора. (Не зависящие от меня причины препятствуют обновлению версии кросс-компилятора с отмеченной проблемой)


person StoneThrow    schedule 03.12.2019    source источник
comment
Важный терминологический момент: в C нет такой вещи, как неявное приведение типов. Существуют неявные преобразования и явные преобразования. Явные преобразования — это приведения типов.   -  person Keith Thompson    schedule 03.12.2019
comment
Какие стандарты C поддерживает gcc 2.95.3? Что, если вы скомпилируете с gcc -std=c99? (Он достаточно старый, поэтому по умолчанию используется -std=gnu89, а в этом режиме <stdbool.h> будет существовать только как расширение.)   -  person Keith Thompson    schedule 03.12.2019
comment
@KeithThompson - Компилятор проблем не поддерживает -std-c99, он генерирует ошибку cc1: unknown C standard 'c99'.   -  person StoneThrow    schedule 03.12.2019
comment
@KeithThompson - спасибо за исправление терминологии; пост фиксируется соответственно.   -  person StoneThrow    schedule 03.12.2019
comment
Я где-то читал, что указатели функций неявно преобразуются в bool. Постараюсь найти источник. Не нашел источник, но нашел вопрос stackoverflow, касающийся этого   -  person smac89    schedule 03.12.2019


Ответы (1)


Да, это ошибка компилятора. Хотя C не имеет неявных преобразований в любом направлении между целочисленными типами и типами указателей, а также неявных преобразований между типами указателей, за исключением особых случаев, таких как в/из указателя в пустоту или из указателя в неквалифицированный в указатель в уточненный, он определяет неявное преобразование в _Bool. (Традиционно многие компиляторы поддерживали такие неявные преобразования в других местах, но это было вредно и не было частью языка C.)

Язык неявного преобразования приведен в разделе 6.5.16.1 Простое назначение:

Должно выполняться одно из следующих условий:

  • левый операнд имеет атомарный, квалифицированный или неквалифицированный арифметический тип, а правый — арифметический тип;
  • левый операнд имеет атомарную, квалифицированную или неквалифицированную версию структуры или типа объединения, совместимую с типом правого;
  • левый операнд имеет атомарный, квалифицированный или неквалифицированный тип указателя, и (учитывая тип, который будет иметь левый операнд после преобразования lvalue) оба операнда являются указателями на квалифицированные или неквалифицированные версии совместимых типов, а тип, на который указывает левый, имеет все квалификаторы типа, указанного справа;
  • левый операнд имеет атомарный, квалифицированный или неквалифицированный тип указателя, и (учитывая тип, который будет иметь левый операнд после преобразования lvalue) один операнд является указателем на объектный тип, а другой является указателем на уточненную или неквалифицированную версию void, а тип, на который указывает левый, имеет все квалификаторы типа, на который указывает правый;
  • левый операнд — это атомарный, квалифицированный или неполный указатель, а правый — константа нулевого указателя; или
  • левый операнд имеет тип атомарный, квалифицированный или неквалифицированный _Bool, а правый является указателем.

В других местах стандарта, где появляется неявное преобразование, оно указано «как бы по присваиванию», ссылаясь на вышеизложенное. Например, в 6.5.2.2 Вызовы функций:

Если выражение, обозначающее вызываемую функцию, имеет тип, который включает в себя прототип, аргументы неявно преобразуются, как если бы они выполнялись присваиванием,...

Обратите внимание, что ваш вопрос на самом деле касается инициализации, которая не является присваиванием в C, а чем-то другим. Тем не менее, 6.7.9 Инициализация ¶11 охватывает это:

Инициализатор скаляра должен быть одним выражением, необязательно заключенным в фигурные скобки. Начальное значение объекта равно значению выражения (после преобразования); Применяются те же ограничения и преобразования типов, что и для простого присваивания, принимая тип скаляра за неквалифицированную версию его объявленного типа.

person R.. GitHub STOP HELPING ICE    schedule 03.12.2019
comment
Удивительно: так что код, который неявно выполняет приведение типов в любом направлении между указателями и целочисленными типами, на самом деле использует расширения компилятора или что-то вроде бесплатной доброты, которую предлагает компилятор (что, как оказалось, является большинством компиляторов)? - person StoneThrow; 03.12.2019
comment
Хм. Использование указателя в логическом контексте всегда было разрешено (if (ptr) { blah }), так что это преобразование не кажется слишком далеким от рельсов. - person Steve Friedl; 03.12.2019
comment
Это неправильно. C специально разрешает неявные преобразования типов указателей в _Bool. См. N1570 6.5.16.1. - person Keith Thompson; 03.12.2019
comment
@KeithThompson: Действительно, это даже в тексте, который я только что добавил. Починю. - person R.. GitHub STOP HELPING ICE; 03.12.2019
comment
@StoneThrow: Да. - person R.. GitHub STOP HELPING ICE; 03.12.2019
comment
@SteveFriedl: это не логический контекст. Он использует выражение с типом указателя в качестве управляющего выражения в условном выражении, и его семантика определена в другом месте таким образом, что это не имеет ничего общего с преобразованием в _Bool. - person R.. GitHub STOP HELPING ICE; 03.12.2019
comment
@KeithThompson: На самом деле мне нужно проверить еще одну вещь: инициализация не является присваиванием, и она может быть там не разрешена. - person R.. GitHub STOP HELPING ICE; 03.12.2019
comment
@R.. Те же правила применяются к простому присваиванию, инициализации, передаче аргументов и операторам return. - person Keith Thompson; 03.12.2019