Требования к поведению указателя к летучести, указывающего на энергонезависимый объект

C11 6.7.3 Типовые classификаторы, пункт 7, гласят:

Объект, который имеет изменчивый тип, может быть изменен способами, неизвестными реализации или имеющими другие неизвестные побочные эффекты. Поэтому любое выражение, относящееся к такому объекту, должно оцениваться строго в соответствии с правилами абстрактной машины, как описано в 5.1.2.3.

В следующем примере объект, доступ к которому в третьей строке относится к вышеуказанному правилу?

int x; volatile int *p = &x; *p = 42; 

Другими словами, действительно ли тот факт, что lvalue *p имеет тип volatile int означает, что к нему относится изменчивый объект, или тот факт, что p указывает на энергонезависимый объект x означает, что компилятор может оптимизировать эти знания и опустить неустойчивый доступ?

Поскольку это может представлять интерес, конкретный случай использования, который мне интересен, выходит за frameworks простой C; он включает атомизацию для синхронизации streamов с использованием конструкций pre-C11 (которые могут быть встроенными asm или просто считаться черным ящиком) для атомного сравнения и замены, со следующей идиомой:

 do { tmp = *p; new = f(tmp); } while (atomic_cas(p, tmp, new) != success); 

Здесь указатель p будет иметь тип volatile int * , но меня беспокоит то, что происходит, когда объект, на который указывает объект, является энергонезависимым, в частности, может ли компилятор преобразовать единственный доступ к *p из tmp = *p в два доступ к следующей форме:

 do { new = f(*p); } while (atomic_cas(p, *p, new) != success); 

что, очевидно, сделает код неправильным. Таким образом, цель состоит в том, чтобы определить, действительно ли все такие объекты с заостренными предметами должны быть volatile int .

    Обновление 18 февраля 2017 года

    Ответ ниже цитирует и обсуждает язык в Стандарте, некоторый противоречивый язык в Обосновании и некоторые комментарии от gnu.cc re противоречие. Существует отчет о дефекте, который по существу имеет соглашение о комитете (хотя и все еще открыто), которое должен сказать стандарт, и что намерение всегда было и что реализации всегда отражали, что важна не волатильность объекта (на Standard), а волатильность (lvalue of) доступа (согласно Обоснованию). (Кредит Олафу за упоминание этого ДР.)

    Резюме отчета о дефектах для версии C11 1.10 Дата: апрель 2016 г. DR 476 изменчивая семантика для lvalues 04/2016 Открыть


    Нет. Поскольку доступ к объекту не является изменчивым.

    Объект p имеет тип указателя на volatile int. Но x не является объектом нестабильного типа. Квалификации на p влияют на то, какие обращения могут быть сделаны через него, но не влияют на тип объекта, на который он указывает. Нет ограничений на доступ к объекту неквалифицированного типа с помощью летучего lvalue. Таким образом, доступ к x через p не является доступом к объекту с изменчивым квалификационным типом.

    (См. 6.7.3. Типовые classификаторы ограничений доступа к объектам квалифицированных типов. Он просто говорит, что вы не можете получить доступ к летучим квалифицированным объектам с помощью неквалифицированного lvalue.)

    С другой стороны, этот пост цитируется из 6.7.3 Обоснования для международных стандартов – Языки программирования – C:

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

    Однако я не могу найти язык в стандарте, который говорит, что семантика основана на типе lvalue. От gnu.org :

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

    [..] из стандарта неясно, обеспечивают ли летучие lvalues ​​больше гарантий в целом, чем нелетучие lvalues, если базовые объекты являются обычными.

    Нет, потому что побочных эффектов нет:

    Даже если семантика *p должна быть нестабильной, стандарт все же говорит:

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

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

    Также имейте в виду

    6.7.3. Определители типов 7 […]. Что представляет собой доступ к объекту, который имеет нестабильный тип, определяется реализацией.

    5.1.2.3 Выполнение программы 8 Более строгие соответствия между абстрактной и фактической семантикой могут быть определены каждой реализацией.

    Таким образом, простое появление летучих значений не говорит вам, что такое «доступ». Вы не имеете права говорить о «единственном доступе к *p от tmp = *p », за исключением случаев документированного поведения реализации.

    Не совсем уверен, но я думаю, что точка – это разница между типом объекта и типом, с которым определяется объект.

    Из C11 (n1570) 6.3.2.1 p1 (сноска опущена, вверху):

    Lvalue – выражение (с типом объекта, отличным от void ), который потенциально обозначает объект; если lvalue не назначает объект при его оценке, поведение не определено. Когда объект имеет определенный тип, тип определяется значением l, используемым для обозначения объекта. […]

    Это значение lvalue, которое определяет тип, который объект имеет для определенного доступа. Напротив, *p не обозначает неопределенный объект. Например, там же. 6.7.3 p6 (emph mine) читает

    […] Если делается попытка обратиться к объекту, определенному с помощью типа с изменчивой квалификацией, с использованием значения lvalue с типом, не относящимся к летучим, поведение не определено. 133)

    133) Это относится к тем объектам, которые ведут себя так, как если бы они были определены с помощью квалифицированных типов, даже если они никогда не были определены как объекты в программе (например, объект с адресом ввода / вывода с отображением памяти).

    Если целью было разрешить оптимизацию кода, цитата в вопросе, вероятно, будет читать объект, который имеет [определяется с помощью] изменчивого типа может быть изменен […]

    «Определение» идентификатора *) определено в п. 5 раздела 6.7.

    Там же. 6.7.3. P7. ( Что представляет собой доступ к объекту, который имеет тип с изменчивой квалификацией, определяется реализацией. ) Дает некоторую свободу для исполнителей, но для меня цель заключается в том, что побочный эффект изменения объекта, обозначенного n следует рассматривать как наблюдаемое посредством соответствующей реализации.

    *) Afaik стандарт не определяет «объект, определенный с (каким-то типом)» в любом месте, поэтому я читаю его как «объект, обозначенный идентификатором, объявленным (некоторым типом) определением».