Почему я получил операцию, которая может быть неопределенной в выражении оператора на С++?

чтобы просто описать проблему, взгляните на код ниже:

int main()
{
    int a=123;
    ({if (a) a=0;});
    return 0;
}

Я получил это предупреждение от [-Wsequence-point]

Line 4: warning: operation on 'a' may be undefined

моя версия g++ 4.4.5

Я буду признателен тому, кто объяснит эту простую проблему.

Кстати, вы можете найти мою исходную программу и исходную проблему в #7 в этом Китайский сайт (не обязательно)

UPD1:

хотя изменение кода на ({if(a) a=0; a;}) может избежать предупреждения, но я понял, что настоящая причина проблемы может быть не в The last thing in the compound statement should be an expression followed by a semicolon.

потому что документальный фильм также сказал If you use some other kind of statement last within the braces, the construct has type void, and thus effectively no value.

пример может показать это:

int main()
{
    int a=123, b;
    ({;});
    ({if (a) b=0;});
    return 0;
}

и этот код не получил предупреждений! поэтому я думаю, что настоящая причина связана с точкой следования.

пожалуйста помоги!

UPD2:

извините @AndyProwl за то, что не принял его ответ, который был принят до UPD1. следуя его совету, я могу задать новый вопрос (UPD1 - новый вопрос, отличный от исходного). Я снова приму его ответ, потому что он все равно избегает предупреждений. :)

Если я решил задать новый вопрос, я обновлю этот вопрос, чтобы добавить ссылку.


person FLanS39    schedule 30.05.2013    source источник
comment
Внутри выражения оператора нет точки последовательности, но вы изменяете там a. Это УБ.   -  person    schedule 30.05.2013
comment
@H2CO3 внутри выражения оператора существуют полные выражения. почему нет точек следования? надеясь, что вы уточните свой комментарий   -  person FLanS39    schedule 01.06.2013


Ответы (1)


Согласно грамматике C++, выражения (возможно, за исключением лямбда-выражений, но это другая история) не могут содержать операторы, включая блочные операторы. Поэтому я бы сказал, что ваш код неправильно сформирован, и если GCC его компилирует, это означает, что это (странное) расширение компилятора.

Вы должны обратиться к справочнику компилятора, чтобы выяснить, какая семантика ему дана (или не дана, как кажется, предполагает сообщение об ошибке) ему.

ИЗМЕНИТЬ:

Как указано Shafik Yaghmour в комментариях, похоже, это расширение GNU. Согласно документации , значение этого «выражения оператора» должно быть значением последнего оператора в блоке, который должен быть оператором выражения:

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

Поскольку блок в вашем примере не содержит оператора выражения в качестве последнего оператора, GCC не знает, как оценить это «выражение оператора» (не путать с «оператором выражения» — это то, что должно отображаться последним в выражении оператора) .

Поэтому, чтобы GCC не жаловался, вы должны сделать что-то вроде:

({if (a) a=0; a;});
//            ^^

Но, честно говоря, я не понимаю, зачем эта штука вообще может понадобиться на C++.

person Andy Prowl    schedule 30.05.2013
comment
Это расширение gcc: stackoverflow.com/questions/3079721/, хотя документы минимальны: gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html ... Я надеялся, что H2C03 разъяснит свой комментарий. - person Shafik Yaghmour; 30.05.2013
comment
Только что скомпилировал образец с gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3, с gcc -Wall -Wsequence-point... ни ошибок, ни предупреждений. Довольно странно. - person Matthieu Rouget; 30.05.2013
comment
@MatthieuM.: Так что это в основном предназначалось для инициализации переменных const до того, как у нас появились лямбда-выражения, верно? - person Andy Prowl; 30.05.2013
comment
Факт @MatthieuRouget очень полезен. Я также сомневаюсь, что это ошибка в конкретной версии gcc, потому что вы можете видеть, что Normal(ans) получает предупреждение, а Normal(a[i][j]) нет в моем исходном коде. - person FLanS39; 30.05.2013
comment
@MatthieuM.: Это должно быть включено в GCC по умолчанию? Я получил error: void value not ignored as it ought to beс вашей линией. - person Matthieu Rouget; 30.05.2013
comment
@MatthieuM.: Тем не менее, я не думаю, что это сработает: в спецификации сказано, что последней частью оператора блока должно быть выражение, за которым следует точка с запятой. Более того, почему бы и нет x ? 0 : 123? - person Andy Prowl; 30.05.2013
comment
@AndyProwl: да, это замена лямбда-выражениям в том, что касается локальных анонимных функций. Мне также нравится использование на странице примера gcc (используя его в макросе, чтобы избежать многократной оценки аргументов макроса). - person Matthieu M.; 30.05.2013
comment
@MatthieuRouget: вы правы, небольшая ошибка с моей стороны (удалил мой комментарий, я не мог его отредактировать), правильное использование: int a = ({ int _z; if (...) _z = 0; else _z = 123; _z; });. - person Matthieu M.; 30.05.2013
comment
@AndyProwl: Что ж, в этом случае тернарный оператор действительно потребуется, но вы можете иметь столько операторов, сколько необходимо в операторе выражения, чтобы вы могли выполнять несколько операций, а не только одно ветвление if. - person Matthieu M.; 30.05.2013
comment
@MatthieuM.: Хорошо, спасибо. Интересно, не знал об этой функции. - person Matthieu Rouget; 30.05.2013
comment
@MatthieuM.: Понятно, но все же - что касается вашего последнего примера - почему бы не сделать: ` int _z; если (...)_z = 0; иначе _z = 123; int a = _z? Perhaps because we would not want to have _z` в области a? - person Andy Prowl; 30.05.2013
comment
@AndyProwl: Да, наверное. В любом случае, теперь это спорно для пользователей C++ 11 благодаря лямбда-выражениям :) - person Matthieu M.; 30.05.2013
comment
Прохладный! согласно коду @AndyProwl, предупреждений больше нет! Буду читать документацию внимательнее. Кстати, выражение оператора является важным расширением gcc, которое широко используется в исходном коде ядра Linux (для макрофункции) - person FLanS39; 30.05.2013
comment
@FLanS39: Почему вы не приняли этот ответ? Это не решает вашу проблему? - person Andy Prowl; 01.06.2013
comment
@AndyProwl очень сожалею об этом. Я пытался отправить вам сообщение, чтобы объяснить, почему я не принимаю его, но я не нашел, как отправить сообщение. - person FLanS39; 01.06.2013
comment
@AndyProwl Я обновил свой вопрос. простите еще раз за мою невежливость. - person FLanS39; 01.06.2013
comment
@FLanS39: Не беспокойтесь о непринятии (вы оставили объяснение, так что все в порядке). Честно говоря, я думаю, что проблема в том, что GCC выдает неправильное сообщение. AFAICT, в вашем коде нет ничего, что могло бы привести к неопределенному поведению. Однако, если вы хотите, чтобы этот вопрос привлек больше внимания, вам, вероятно, придется задать другой вопрос и связать его с этим, или предложить вознаграждение - иначе никто не сможет заметить, что ваш вопрос был отредактирован (кроме меня , потому что меня уведомили, что мой ответ не принят). - person Andy Prowl; 01.06.2013
comment
@AndyProwl, ваш совет очень полезен для меня, новичка в stackoverflow! большое спасибо! Я могу отредактировать свой вопрос в ближайшее время - person FLanS39; 01.06.2013