Undefined/Unspecified/Предупреждения о поведении, определенные при реализации?

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

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

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

Ответ 1

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

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

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

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

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

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

Скажем, у вас есть следующее:

#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 говорится в комментариях, компилятор не может проверять единицы перевода для поведения undefined. Классический пример: объявляет переменную как указатель в одном файле и определяет ее как массив в другой, см. comp.lang.c FAQ 6.1.

Ответ 2

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:

Быстрое чтение man page показывает, что -Wsequence-point сделает это, если вы не хотите, чтобы -Wall для некоторых причина.

Ответ 3

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

§1.4.1:
Набор диагностируемых правил состоит из всех синтаксических и семантических правил в этом Международном стандарте, за исключением тех правил, которые содержат явное обозначение, что "никакой диагностики не требуется" или которые описываются как результат "undefined поведения".

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

Ответ 4

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

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

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

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

Ответ 5

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

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

Ответ 6

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

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

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