Не определено / Не указано / Определено реализацией предупреждений о поведении? - PullRequest
5 голосов
/ 20 февраля 2010

Может ли компилятор предупреждать (даже лучше, если он выдает ошибки), когда он замечает оператор с неопределенным / неуказанным / определяемым реализацией поведением?

Возможно, чтобы пометить оператор как ошибку, стандарт должен сказатьтак, но это может предупредить кодера по крайней мере.Есть ли технические трудности при реализации такой опции?Или это просто невозможно?

Причина, по которой я получил этот вопрос, заключается в том, что в выражениях типа a[i] = ++i; не будет ли он знать, что код пытается ссылаться на переменную и модифицировать ее в том же выражении, перед тем какточка последовательности достигнута.

Ответы [ 6 ]

7 голосов
/ 20 февраля 2010

Все сводится к

  • Качество выполнения : чем точнее и полезнее предупреждения, тем лучше. Компилятор, который всегда печатал: «Эта программа может вызывать или не вызывать неопределенное поведение» для каждой программы, а затем компилировал ее, довольно бесполезен, но соответствует стандартам. К счастью, никто не пишет такие компиляторы, как эти: -).

  • Простота определения : компилятор не может легко определить неопределенное поведение, неопределенное поведение или поведение, определяемое реализацией. Допустим, у вас есть стек вызовов глубиной 5 уровней с аргументом const char *, передаваемым из верхнего уровня в последнюю функцию в цепочке, и последняя функция вызывает printf() с этим const char * в качестве первого аргумент. Вы хотите, чтобы компилятор проверил, что const char *, чтобы убедиться, что это правильно? (Предполагая, что первая функция использует литеральную строку для этого значения.) Как насчет того, когда const char * читается из файла, но вы знаете, что файл всегда будет содержать действительный спецификатор формата для печатаемых значений?

  • Коэффициент успеха : компилятор может обнаруживать множество конструкций, которые могут быть или не быть неопределенными, неуказанными и т. Д .; но с очень низким «успехом». В этом случае пользователь не хочет видеть много сообщений «может быть неопределенным» - слишком много ложных предупреждающих сообщений может скрывать настоящие предупреждающие сообщения или побуждать пользователя к компиляции с настройкой «низкий уровень предупреждения». Это плохо.

В вашем конкретном примере gcc выдает предупреждение о том, что "может быть не определено". Он даже предупреждает о несоответствии формата printf().

Но если вы надеетесь на компилятор, который выдает диагностику для всех неопределенных / неуказанных случаев, неясно, будет ли это работать / может работать.

Допустим, у вас есть следующее:

#include <stdio.h>
void add_to(int *a, int *b)
{
    *a = ++*b;
}

int main(void)
{
    int i = 42;
    add_to(&i, &i); /* bad */
    printf("%d\n", i);
    return 0;
}

Должен ли компилятор предупреждать вас о *a = ++*b; строке?

Как говорит gf в комментариях, компилятор не может проверять единицы перевода на наличие неопределенного поведения. Классический пример - объявление переменной в качестве указателя в одном файле и определение ее в виде массива в другом, см. comp.lang.c FAQ 6.1 .

2 голосов
/ 20 февраля 2010

Разные компиляторы ловят разные условия; большинство компиляторов имеют опции уровня предупреждения, в частности, GCC имеет много, но -Wall -Werror включит большинство полезных и приведет их к ошибкам. Используйте \ W4 \ WX для аналогичной защиты в VC ++.

В GCC Вы можете использовать -ansi -pedantic, но педантичный - это то, что он говорит, и он вызовет много не относящихся к делу проблем и затруднит использование большого количества стороннего кода.

В любом случае, поскольку компиляторы отлавливают разные ошибки или выдают разные сообщения для одной и той же ошибки, поэтому полезно использовать несколько компиляторов, не обязательно для развертывания, но в качестве статического анализа для плохого человека. Другой подход к коду C - попытаться скомпилировать его как C ++; более строгая проверка типов в C ++ обычно приводит к лучшему коду на C; но будьте уверены, что если вы хотите, чтобы компиляция C работала, не используйте исключительно компиляцию C ++; Вы, вероятно, представите специфические особенности C ++. Опять же, это не нужно развертывать как C ++, а просто использовать как дополнительную проверку.

Наконец, компиляторы обычно строятся с балансом производительности и проверкой ошибок; для исчерпывающей проверки потребуется время, которое многие разработчики не примут. По этой причине существуют статические анализаторы, для C существует традиционная линейка и шина с открытым исходным кодом. C ++ более сложен для статического анализа, а инструменты часто очень дороги. Одним из лучших, которые я использовал, является QAC ++ от Programming Research. Я не знаю ни одного бесплатного или открытого анализатора C ++ с какой-либо репутацией.

2 голосов
/ 20 февраля 2010

gcc предупреждает в этой ситуации (по крайней мере, с -Wall):

#include <stdio.h>

int main(int argc, char *argv[])
{
  int a[5];
  int i = 0;

  a[i] = ++i;

  printf("%d\n", a[0]);

  return 0;
}

Дает:

$ make
gcc -Wall main.c -o app
main.c: In function ‘main’:
main.c:8: warning: operation on ‘i’ may be undefined

Edit:

Краткое чтение справочной страницы показывает, что -Wsequence-point сделает это, если по какой-то причине вы не хотите -Wall.

1 голос
/ 20 февраля 2010

Наоборот, компиляторы не необходимы для постановки любого вида диагностики неопределенного поведения:

§1.4.1:
Набор диагностируемых правил состоит из всех синтаксических и семантических правил в этом международном стандарте, за исключением тех правил, которые содержат явное обозначение, что «диагностика не требуется» или которые описаны как приводящие к «неопределенному поведению». 1009 *

Акцент мой. Хотя я согласен, что это может быть неплохо, у компилятора достаточно проблем с попыткой соответствовать стандартам, не говоря уже о том, чтобы научить программиста программировать.

0 голосов
/ 20 февраля 2010

Если ваш компилятор не предупредит об этом, вы можете попробовать Linter.

Шиномонтаж бесплатный, но проверяет только C http://www.splint.org/

Gimpel Lint поддерживает C ++, но стоит 389 долларов США - может быть, ваша компания сможет убедить вас купить копию? http://www.gimpel.com/

0 голосов
/ 20 февраля 2010

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

Вы можете позвонить в GCC с флагом -Wall, чтобы увидеть больше этого.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...