Предупреждения поведения Undefined/Unspecified/Implementation-defined?

Разве компилятор не может предупредить (еще лучше, если он бросает ошибки), когда он замечает оператор с undefined/unspecified/implementation-defined поведением?

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

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

5
задан legends2k 20 February 2010 в 06:56
поделиться

6 ответов

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

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

  • Простота определения : компилятору может быть нелегко определить неопределенное поведение, неопределенное поведение или поведение, определяемое реализацией. Допустим, у вас есть стек вызовов глубиной 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 .

7
ответ дан 13 December 2019 в 05:34
поделиться

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

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

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

0
ответ дан 13 December 2019 в 05:34
поделиться

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

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

0
ответ дан 13 December 2019 в 05:34
поделиться

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

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

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

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

2
ответ дан 13 December 2019 в 05:34
поделиться

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;
}

Gives:

$ 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.

2
ответ дан 13 December 2019 в 05:34
поделиться

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

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

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

1
ответ дан 13 December 2019 в 05:34
поделиться