Является ли "* p = ++ (* q)" неопределенным, когда p и q указывают на один и тот же объект? - PullRequest
12 голосов
/ 26 августа 2010

прочитав о точках последовательности, я узнал, что i = ++i не определено.

Так как насчет этого кода:

int i;
int *p = &i;
int *q = &i;
 *p = ++(*q);           // that should also be undefined right?

Скажем, если инициализация p и q зависит от некоторых(сложное) состояние.И они могут указывать на один и тот же объект, как в предыдущем случае.Что случится?Если он не определен, какие инструменты мы можем использовать для обнаружения?

Редактировать: Если два указателя не должны указывать на один и тот же объект, можем ли мы использовать ограничение C99?Что значит «строгий»?

Ответы [ 5 ]

12 голосов
/ 26 августа 2010

Да, это неопределенное поведение - у вас есть две модификации объекта без точки последовательности между ними. К сожалению, проверка этого автоматически очень трудна - лучшее, что я могу придумать, это добавить assert(p != q) прямо перед этим, что, по крайней мере, даст чистую ошибку времени выполнения, а не что-то худшее. Проверка этого во время компиляции неразрешима в общем случае.

4 голосов
/ 26 августа 2010

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

*q += 1;
*p = *q;
2 голосов
/ 26 августа 2010

Глава 5 Выражения

Точка 4:

За исключением отмеченных случаев, порядок вычисления операндов отдельных операторов и подвыражений отдельных выражений, а также порядок возникновения побочных эффектов не определены. Между предыдущей и следующей точкой последовательности скалярному объекту должно быть сохранено сохраненное значение, измененное не более одного раза путем оценки выражения . Кроме того, предварительное значение должно быть доступно только для определения значения, которое будет сохранено. Требования этого параграфа должны выполняться для каждого допустимого порядка подвыражений полного выражения; в противном случае поведение не определено.

[ Example:
  i = v[i ++];           / / the behavior is undefined
  i = 7 , i++ , i ++;    / / i becomes 9
  i = ++ i + 1;          / / the behavior is undefined 
  i = i + 1;             / / the value of i is incremented
—end example ]

В результате это неопределенное поведение:

int i;
int *p = &i;
int *q = &i;
*p = ++(*q);   // Bad Line

В «Плохой линии» скалярный объект «i» обновляется более одного раза во время вычисления выражения. Тот факт, что к объекту «i» обращаются косвенно, не меняет правила.

2 голосов
/ 26 августа 2010

Выражение такое же, как i = ++ i.Единственный инструмент, который может обнаружить это ваша голова.С силой приходит ответственность.

1 голос
/ 26 августа 2010

Хороший вопрос. Одна вещь, которую вы подчеркнули, это «точки последовательности», чтобы процитировать с этого сайта

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

И, кроме того, вышеприведенное выражение аналогично тому же, поэтому поведение равно undefined , поскольку для инструментов для отслеживания этого значения - ноль, конечно, есть splint , чтобы назвать одно в качестве примера, но это стандарт C, так что, возможно, в инструменте есть скрытая опция, о которой я еще не слышал, возможно, Gimpel PC Lint или Riverblade Visual Вам может помочь lint, хотя я признаю, что в нем ничего не говорится о отслеживании неопределенного поведения в этом отношении.

Между прочим, версия 4.3.3 компилятора GCC имеет эту опцию -Wsequence-point как часть предупреждения об ошибках .. это на моем Slackware 13.0 box ...

Это просто показывает, что код может выглядеть невооруженным глазом и будет прекрасно компилироваться, но позже может вызвать головную боль, лучший способ сделать это - иметь обзор кода, который может обнаружить вещи, которые компилятор может не выбрать читай, это лучшее оружие выбора!

...