Я думаю, что ответ "нет", но с точки зрения компилятора я не понимаю, почему.
Я сделал очень простой код, который плохо выводит диагностику компилятора (как clang, так и gcc), но я хотел бы получить подтверждение того, что код не был отформатирован до того, как я сообщаю о неправильной диагностике. Я должен указать, что это не ошибки компилятора, вывод корректен во всех случаях, но я сомневаюсь в предупреждениях.
Рассмотрим следующий код:
#include <iostream>
int main(){
int b,a;
b = 3;
b == 3 ? a = 1 : b = 2;
b == 2 ? a = 2 : b = 1;
a = a;
std::cerr << a << std::endl;
}
Назначение a
- это тавтология, означающая, что a
будет инициализироваться после двух тернарных операторов независимо от b
. GCC совершенно доволен этим кодом. Кланг слабее умнее и видит что-то глупое (warning: explicitly assigning a variable of type 'int' to itself [-Wself-assign]
), но не имеет большого значения.
Теперь то же самое (семантически, по крайней мере), но более короткий синтаксис:
#include <iostream>
int main(){
int b,a = (b=3,
b == 3 ? a = 1 : b = 2,
b == 2 ? a = 2 : b = 1,
a);
std::cerr << a << std::endl;
}
Теперь компиляторы дают мне совершенно разные предупреждения. Клэнг больше не сообщает ничего странного (что, вероятно, правильно из-за предшествующей скобки). gcc немного страшнее и говорит:
test.cpp: In function ‘int main()’:
test.cpp:7:15: warning: operation on ‘a’ may be undefined [-Wsequence-point]
Но это правда? Это предупреждение о последовательности указывает на то, что инструкции, разделенные комой, обрабатываются не так же на практике, но я не знаю, должны ли они или нет.
И он становится более странным, меняя код на:
#include <iostream>
int main(){
int b,a = (b=3,
b == 3 ? a = 1 : b = 2,
b == 2 ? a = 2 : b = 1,
a+0); // <- i just changed this line
std::cerr << a << std::endl;
}
а затем вдруг clang понял, что может быть что-то подозрительное с a
:
test.cpp:7:14: warning: variable 'a' is uninitialized when used within its own initialization [-Wuninitialized]
a+0);
^
Но не было проблемы с a
до... По некоторым причинам clang не может определить тавтологию в этом случае. Опять же, это может быть просто потому, что они больше не являются полными заявлениями.
Проблемы:
- Этот код действителен и определен (во всех версиях)?
- Как обрабатывается список разделенных запятыми операторов? Должен ли он отличаться от первой версии кода с явными утверждениями?
- - это право GCC сообщать о проблемах с поведением и причинами последовательности undefined? (в этом случае clang отсутствует какая-то важная диагностика). Я знаю, что он говорит может, но все же...
- означает, что
a
может быть неинициализирован в последнем случае? (тогда он должен иметь такую же диагностику для предыдущего случая)
Изменить и комментарии:
- Я получаю несколько (законных) комментариев, что этот код ничего, кроме простого. Это верно, но дело в том, что компиляторы неправильно диагностируют, когда они сталкиваются с разделителями-запятыми в инициализаторах. Это плохо. Я сделал код более полным, чтобы избежать комментариев "вы пробовали этот синтаксис...". Можно было бы написать гораздо более реалистичную и понятную для человека версию проблемы, которая бы показала неправильную диагностику, но я думаю, что эта версия показывает больше информации и более полная.
- в наборе тестов для компилятора-пытки, это будет считаться очень понятным и читаемым, они намного хуже:) Нам нужен такой код для тестирования и оценки компиляторов. Это не выглядит красивым в производственном коде, но здесь дело не в этом.