Это хорошо определенный код? - PullRequest
10 голосов
/ 17 мая 2011

Я все еще немного растерялся после прочтения этой темы. Хорошо ли определено следующее выражение C ++ *d++ = ~(*d);? Да, я знаю, что составные выражения, подобные этому, ужасны ... Я их не писал.

Я вижу небольшую разницу в сгенерированной сборке, когда сравниваю ее с:

*d = ~(*d);
d++;

Сборка:

*d++ = ~(*d);
0x83384    LDR           R3,[R0 <d>,4]        <<diff
0x83388    ADD           R1 <c>, R1 <c>, 1
0x8338c    MVN           R3, R3
0x83390    STR           R3,[R0 <d>],4

против

*d = ~(*d);
d++;
0x83384   LDR           R3,[R0 <d>]
0x83388   ADD           R1 <c>, R1 <c>, 1
0x8338c   MVN           R3, R3
0x83390   STR           R3,[R0 <d>],4

Спасибо!

Ответы [ 3 ]

11 голосов
/ 17 мая 2011

Ваше выражение имеет неопределенное (в отличие от неопределенное ) поведение.Код ассемблера также может играть 9-й Бетховен и при этом соответствовать стандарту.

Из Священного Стандарта, глава 5, стих 4:

Между предыдущей и следующей последовательностью указывается точка aСкалярный объект должен иметь свое сохраненное значение, измененное не более одного раза путем вычисления выражения.

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

См.к превосходной экспозиции @Prasoon Saurav там для более подробной информации.

9 голосов
/ 17 мая 2011
*d++ = ~(*d);

В этом выражении ни у одного объекта нет нового значения, сохраненного в нем более одного раза. Значение d + 1 сохраняется в d как побочный эффект оператора приращения (d++) и значения объекта, на который указывает d, до того, как это приращение записывается оператором присваивания.

Проблема в том, что d читается не только для определения значения, которое должно быть записано обратно (то есть d + 1), но также для чтения адреса для чтения в правом подвыражении. ~(*d).

Это нарушает третье предложение ИСО / МЭК 14882: 2003 5 [expr] / 4 (первое предложение опущено для краткости):

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

1 голос
/ 17 мая 2011

Вы просто не знаете, когда оценивается ++. Я полагаю, ваш компилятор оценивает его до ~(*d), что приводит к

*d = ~(*(d+1));

Таким образом, ваше расхождение.

...