2014-01-11 7 views
14

С99 §6.5 ВыражениеТочки последовательности и побочные эффекты: Тихое изменение в C11?

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

(2) Между предыдущей и следующей точкой последовательности объект должен иметь неизмененное значение хранимого значения не более одного раза путем оценки выражения. 72) Кроме того, предыдущее значение должно быть считано только для определения значения, которое необходимо сохранить. 73)

с сносками

72) флаг состояния с плавающей точкой не является объектом и может быть установлен более чем один раз в выражении.

73) Этот пункт оказывает неопределенные выписки такие выражения, как

i = ++i + 1; 
    a[i++] = i; 

, позволяя

i = i + 1; 
    a[i] = i; 

где C11 §6.5 изменяется на (текст (1) имеет дополнение):

(1) [...] Вычисления значений операндов оператора: упорядочивается перед вычислением значения результата оператора.

(2) Если побочный эффект скалярного объекта не зависит от другого побочного эффекта для одного и того же скалярного объекта или вычисления значения с использованием значения одного и того же скалярного объекта, поведение не определено. Если существует несколько допустимых порядков подвыражений выражения, поведение не определено, если такой побочный эффект без последствий происходит в любом из упорядочений. 84)

, где сноска 84 в C11 такая же, как 73 в C99.

Я немного смущен ... Я читал C11 (2) как «[...] либо (другой побочный эффект для одного и того же скалярного объекта), либо (вычисление значения с использованием значения одного и того же скалярного объекта) [... ], который, кажется, даже не позволяет foo = ++i (есть побочный эффект, и мы используем значение в зависимости от измененного объекта). Я не носитель языка, однако, было бы неплохо, если бы я мог сказать, как это предложение должно быть «разобрано». Я понимаю C99, но я не совсем понимаю формулировку C11.

В любом случае, реальный вопрос: это изменение от C99 до C11, или эти эквиваленты? И если да, то почему это было изменено? А если нет, может ли кто-нибудь привести пример выражения, которое является UB в C99, но не в C11 или наоборот?

+0

Помните, что C11 должен иметь дело с потоками и «атомными» типами и т. П., Что является частью причины изменения формулировки. –

ответ

4

C11 (а также C++ 11) полностью переработал формулировку последовательности, поскольку C11 теперь имеет потоки, и он должен был объяснить, что последовательность между потоками, которые обращаются к тем же данным. Цель комитета заключалась в том, чтобы сохранить совместимость с C99 для случая, когда есть только один поток выполнения.

Давайте посмотрим на версию C99:

  1. Между предыдущей и следующей точкой последовательности

  2. объектную

  3. должен иметь

  4. его сохраненное значение модифицированного не более одного раза

  5. путем оценки экспрессии.

по сравнению с нового текстом

Если побочный эффект на

различной terminolgie для 4, модифицирующего сохраненного значения

скалярного объект

ограничение предыдущей редакции в 2. Новый текст говорит только что-то о скалярных объектов

является unsequenced относительно либо

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

другой побочный эффект на той же скалярного объекта

объект разрешено только быть изменен один раз

или вычисление значения с использованием значения одного и того же скалярного объекта,

или считывание значения может не отображаться одновременно с модификацией

поведение не определено.

«Должно» в 3. говорит это неявно. Все «должны» привести к UB, если они не выполняются.

2

Это объяснение foo = ++i, но на самом деле ответ на вопрос.


Приоритет префикса определяется в терминах назначения соединений, см. 6.5.3/2

Выражение ++E эквивалентно (E+=1)

для назначения в общем, есть гарантия в 6.5.16/3

Побочный эффект обновления сохраненного значения левого операнда , упорядоченный после вычислений значений левого и правого операндов. Оценки не зависят от операндов.

So foo = ++i равнозначно foo = (i+=1). Внутренний i+=1 требует модификации i, подлежащей секвенированию после вычисления i+1. Полученное значение выражения (i+=1) указано в 6.5.16/3, как:

Выражения присваивания имеет значение левого операнда после присваивания, но не является именующим.

Это кажется как будто это требует вычисления значения из i+=1 для секвенирования после модификации i, и в C++ 11, это даже гарантировано явно [expr.ass]/1

Во всех случаях назначение выполняется после значения вычисления правого и левого операндов и перед вычислением значения выражения присваивания.

(который понятнее для меня, но я знаю, что C++ гораздо лучше, чем C)

Модификация i секвенировали до вычисления значения из i+=1, поэтому мы не имеем UB доступа значение ++i в foo = ++i (так как вычисление значения левого и правого операндов foo = x секвенировано до модификации foo).

1

Насколько я понимаю,

Если побочный эффект на скалярной объекта unsequenced относительно ... вычисления значения с использованием значения одного и того же скалярного объекта

здесь не применяется из-за (1), в котором говорится, что

Расчет значений операндов оператора секвенирован bef вычисляет значение результата оператора.

Иными словами, результат определяется как «прийти позже», i. е. it is sequenced.

3

Я немного смущен ... Я читал C11 (2) как «[...] либо (другой побочный эффект для одного и того же скалярного объекта), либо (вычисление значения с использованием значения одного и того же скалярного объекта) [...] ", который, кажется, даже не позволяет foo = ++i (есть побочный эффект, и мы используем значение в зависимости от измененного объекта).

Если вы читали стандартную цитату тщательно

Если побочный эффект на скалярной объекта unsequenced по отношению к любой другой побочный эффект от того же скалярного объекта или вычисление значения, используя значение одного и того же скалярного объекта, поведение не определено. Если существует несколько допустимых порядков подвыражений выражения, поведение не определено, если такой побочный эффект без последствий происходит в любом из упорядочений. 84)

, то вы обнаружите, что ваша формулировка должна быть:

Если побочный эффект на скалярной объекта unsequenced по отношению к любой (другой побочный эффект на же скалярный объект) или (вычисление значения с использованием значения того же скалярного объекта).

Это означает, что foo = ++i является определенным заявлением. Это правда, что есть побочный эффект на i (также на foo), но ничего нет неестественный здесь для объекта i.

+0

Два побочных эффекта (приращение 'i' и обновление' foo') не подвержены влиянию, но это не вызывает никаких проблем, поскольку они являются отдельными объектами. –

+0

Спасибо, я начинаю понимать C11 (2). Но все же, эквивалент C99 и C11 здесь (единственное доказательство, что это не так, является встречным примером)? – mafso

+0

@KeithThompson; Два побочных эффекта не имеют никакого значения, но для отдельного объекта (для 'i' или' foo') это не имеет значения. Вот почему я написал * здесь ничего не произошло *. – haccks