Разделяются ли запятые заявления, считающиеся полными заявлениями? (и другие диагностические проблемы) - программирование
Подтвердить что ты не робот

Разделяются ли запятые заявления, считающиеся полными заявлениями? (и другие диагностические проблемы)

Я думаю, что ответ "нет", но с точки зрения компилятора я не понимаю, почему.

Я сделал очень простой код, который плохо выводит диагностику компилятора (как 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 может быть неинициализирован в последнем случае? (тогда он должен иметь такую ​​же диагностику для предыдущего случая)

Изменить и комментарии:

  • Я получаю несколько (законных) комментариев, что этот код ничего, кроме простого. Это верно, но дело в том, что компиляторы неправильно диагностируют, когда они сталкиваются с разделителями-запятыми в инициализаторах. Это плохо. Я сделал код более полным, чтобы избежать комментариев "вы пробовали этот синтаксис...". Можно было бы написать гораздо более реалистичную и понятную для человека версию проблемы, которая бы показала неправильную диагностику, но я думаю, что эта версия показывает больше информации и более полная.
  • в наборе тестов для компилятора-пытки, это будет считаться очень понятным и читаемым, они намного хуже:) Нам нужен такой код для тестирования и оценки компиляторов. Это не выглядит красивым в производственном коде, но здесь дело не в этом.
4b9b3361

Ответ 1

5 выражений

10 В некоторых контекстах выражение появляется только для его побочных эффектов. Такое выражение называется отброшенным значением выражение. Выражение оценивается и его значение отбрасывается

5.18 Comma operator [expr.comma]

Пара выражений, разделенных запятой, оценивается слева направо; левое выражение является выражением отбрасываемого значения (п. 5).83 Каждый вычисление значения и побочный эффект, связанный с левым выражением секвенируется перед вычислением каждого значения и связанного с ним побочного эффекта с правильным выражением. Тип и значение результата - это тип и значение правильного операнда; результат имеет одинаковую ценность как его правый операнд и является битовым полем, если его правый операнд это glvalue и бит-поле.

Мне кажется, что в вашем заявлении нет ничего плохого.

Более внимательно рассмотрев предупреждение g++, может быть undefined, что говорит мне, что анализатор недостаточно умен, чтобы убедиться, что a=1 гарантированно будет оценен.