В стандарте C11 ISO/IEC 9899: 2011 (E) указаны следующие ограничения для простых назначений в п. 6.5.16.1/1:
Одно из следующего:
- левый операнд имеет атомный, квалифицированный или неквалифицированный арифметический тип, а правый имеет арифметический тип;
- левый операнд имеет атомную, квалифицированную или неквалифицированную версию структуры или объединения тип, совместимый с типом права;
- левый операнд имеет атомный, квалифицированный или неквалифицированный тип указателя и (учитывая тип, который будет иметь левый операнд после преобразования lvalue) оба операнда указатели на квалифицированные или неквалифицированные версии совместимых типов, а тип слева - все определители типа, на которые указывает справа;
- левый операнд имеет атомный, квалифицированный или неквалифицированный тип указателя и (учитывая тип, который будет иметь левый операнд после преобразования lvalue), один операнд является указателем к типу объекта, а другой - указатель на квалифицированную или неквалифицированную версию void, а тип, на который указывает левый, имеет все квалификаторы типа, указывающего на по праву;
- левый операнд является атомарным, квалифицированным или неквалифицированным указателем, а право - нулевым постоянная указателя; или
- левый операнд имеет тип атомный, квалифицированный или неквалифицированный
_Bool
, а правый - указатель.
Меня интересует случай, когда обе стороны являются указателями на несовместимые типы, отличные от void
. Если я правильно понимаю, это должно, по крайней мере, вызвать UB, поскольку оно нарушает это ограничение. Один пример для несовместимых типов должен быть (согласно §6.2.7 и §6.7.2) int
и double
.
Следовательно, следующая программа должна быть нарушена:
int main(void) {
int a = 17;
double* p;
p = &a;
(void)p;
}
Оба gcc и clang предупреждают о "-Wincompatible-pointer-types", но не прерывают компиляцию (компиляция с помощью -std=c11 -Wall -Wextra -pedantic
).
Аналогично, следующая программа только приводит к предупреждению "-Wint-conversion", при компиляции просто отлично.
int main(void) {
int a;
double* p;
p = a;
(void)p;
}
Исходя из С++, я ожидал, что для любого из этих тестовых случаев потребуется компиляция. Есть ли причина, по которой любая из программ будет стандартно-правовой? Или существуют ли по крайней мере значительные исторические причины для поддержки этого стиля кода даже при отключении развлекательных расширений GNU C, явно используя -std=c11
вместо -std=gnu11
?