Это будет длинный, чтобы контекстуализировать его и предоставить как можно больше информации, я должен пробираться через различные ссылки и цитаты - как это часто бывает, когда мы входим в C/С++ Standard Rabbit Hole. Если у вас есть лучшие цитаты или какие-либо другие улучшения в этом посте, пожалуйста, дайте мне знать. Но для подведения итогов, вы можете обвинить @ zwol, чтобы я опубликовал это;-), и цель состоит в том, чтобы найти правду из двух предложения:
- Сделайте C и (путем импорта, см. комментарии) Стандарты С++ требуют, чтобы обращения через
volatile *
илиvolatile &
должны ссылаться на объект, первоначально объявленныйvolatile
, чтобы иметьvolatile
семантику? - Или обращается к объекту, не содержащему
volatile
, через указатель/ссылкуvolatile
, достаточный/предполагаемый, чтобы заставить указанные обращения вести себя так, как если бы объект был объявленvolatile
?
И в любом случае, если (по-видимому) формулировка несколько неоднозначна по сравнению с намерением - , можем ли мы понять, что в самих Стандартах было четко указано?
1-я из этих взаимно исключающих интерпретаций более распространена, и это не совсем без оснований. Тем не менее, я надеюсь показать, что существует значительное количество "разумных сомнений" в пользу второго - особенно когда мы возвращаемся к некоторым предыдущим отрывкам в "Обосновании" и "Рабочих документах".
Принятая мудрость: сам упомянутый объект должен быть объявлен volatile
Вчера популярный вопрос Является ли определение "volatile" этой изменчивой или имеет GCC, имеющую некоторые стандартные проблемы соответствия? возникла, предположив, что ссылка volatile
даст volatile
на реферере не volatile
, но обнаружив, что он этого не сделал или сделал в разной степени и непредсказуемым образом.
Принятый ответ изначально заключался в том, что имел значение только заявленный тип референта. Это и большинство комментариев, похоже, согласны с тем, что эквивалентные принципы находятся в игре, как мы хорошо знаем для const
: поведение будет только volatile
(или определено вообще), если ссылка имеет ту же самую cv-квалификацию, что и упомянутый объект:
Ключевым словом в этом проходе является объект.
volatile sig_atomic_t flag;
- неустойчивый объект.*(volatile char *)foo
- это просто доступ через l volue с изменчивой квалификацией, и стандарт не требует наличия специальных эффектов. - zwol
Эта интерпретация, как представляется, довольно широко распространена, как видно в ответах на этот похожий, но, надеюсь, не дублирующий вопрос: Требования к поведению указателя к летучей ориентации к энергонезависимому объекту. Но там есть неопределенность: сразу же после ответа "нет" , он говорит "возможно" ! В любом случае... пусть проверяет Стандарт, чтобы увидеть, на что основан "нет" .
Что говорит стандарт... или не
C11, N1548, §6.7.3. В то время как ясно, что UB получает доступ к объекту , определенному с помощью volatile
или const
, с помощью указателя, который не делится указанным квалификатором...
6 Если предпринимается попытка изменить объект, определенный с помощью
const
-qualified type, используя значение lvalue с не-t211 > -qualified type, поведение undefined, Если делается попытка ссылаться на объект, определенный сvolatile
-qualified type, используя значение lvalue с классомvolatile-
, поведение undefined. (133)
... Стандарт, похоже, явно не упоминает противоположный сценарий, а именно для volatile
. Более того, при суммировании volatile
и операций на нем он теперь говорит об объекте, в котором имеет volatile
-qualified type:
7 Объект , имеющий
volatile
-qualified type, может быть изменен способами, неизвестными реализации или имеющими другие неизвестные побочные эффекты. Поэтому любое выражение, относящееся к такому объекту, должно оцениваться строго в соответствии с правилами абстрактной машины, как описано в 5.1.2.3. Кроме того, в каждой точке последовательности значение, сохраненное последним в объекте, должно совпадать с значением, предписанным абстрактной машиной, за исключением измененных неизвестными факторами, упомянутыми ранее. (134) Что представляет собой доступ к объекту сvolatile
-qualified тип определяется реализацией.
Предполагаем ли мы, что "имеет" эквивалентно "было определено с"? или может "есть" см. комбинацию объектных и ссылочных квалификаторов?
В комментариях комментировался вопрос с такой формулировкой:
От n1548 §6.7.3 ¶6 стандарт использует фразу "объект, определенный с помощью нестабильного типа", чтобы отличить его от "lvalue с нестабильным". К сожалению, этот "объект, определенный с" по сравнению с "lvalue" разграничением не переносится, а в стандарте затем используется "объект, который имеет нестабильный тип", и говорит, что "что представляет собой доступ к объекту, который имеет нестабильный тип определяется реализацией" (для ясности можно было сказать "lvalue" или "объект, определенный с" ). Ну что ж. - Дитрих Эпп
Параграф 4 того же раздела, по-видимому, реже цитируется, но может иметь значение, как мы увидим в следующем разделе.
Разумное сомнение: Is/был указателем/ссылкой volatile
, предназначенным для предоставления семантики volatile
при ее разыменовании?
В вышеупомянутом ответе есть комментарий, в котором автор приводит более раннее выражение Комитета, в котором ставится под сомнение идея "ссылка должна соответствовать референту":
Интересно, что там есть одно предложение [ C99 Обоснование для
volatile
], что означает, что комитет означает*(volatile T*)x
, чтобы заставить один доступ кx
рассматриваться как изменчивый; но фактическая формулировка стандарта не достигает этого. - zwol
Мы можем найти немного больше информации об этом фрагменте Обоснования из второго вышеупомянутого потока: Требования к поведению указателя к летучести, указывающего на энергонезависимый объект
С другой стороны, этот пост цитирует из 6.7.3 Обоснования для международного стандарта - Языки программирования - C:
Приведение значения к квалифицированному типу не влияет; квалификация (volatile, say) может не влиять на доступ, так как это произошло до случая. Если необходим доступ к энергонезависимому объекту используя изменчивую семантику, метод заключается в том, чтобы указать адрес объект к соответствующему типу-указателю, а затем разыменованию этот указатель.
- philipxy
И из этот поток байтов, мы ссылаемся на C99 s6.7.3 p3 - aka C11 p4 - и этот анализ:
Данный параграф находится непосредственно перед разделом 6.7.3.1 в обоснованном документе. Если вам также нужно указать из самого стандартного документа, укажите 6.7.3 p3:
Свойства, связанные с квалифицированными типами, имеют смысл только для выражений, которые являются lvalues.
Выражение
(volatile WHATEVER) non_volatile_object_identifier
не является значением lvalue, поэтому "изменчивый" классификатор не имеет смысла.Обратно, выражение
* (volatile WHATEVER *) & non_volatile_object_identifier
является lvalue (он может быть помещен в левую часть оператора присваивания), поэтому свойство "изменчивого" квалификатора имеет в этом случае свое предполагаемое значение.- Тим Ренч
Существует очень конкретная демонстрация, поддерживающая эту идею, с учетом 1-го связанного вопроса, в WG Paper N1381. Это ввело приложение memset_s()
, чтобы сделать то, что хотел OP - гарантировать неавтоматизированное заполнение памяти. При обсуждении возможных реализаций, похоже, эта идея поддерживает идею опускания любого требования - использование указателем volatile
для изменения объекта не volatile
должно генерировать код на основе классификатора указатель, независимо от указанного объекта...
- Независимое от платформы решение "безопасная память":
void *secure_memset(void *v, int c , size_t n) {
volatile unsigned char *p = v;
while (n--) *p++ = c;
return v;
}
Этот подход предотвратит оптимизацию очистки памяти и он должен работать на любой стандартной совместимой платформе.
... и что компиляторы, которые не делают этого, находятся в уведомлении...
Недавно было отмечено, что некоторые компиляторы нарушают стандарт, не всегда соблюдая квалификатор
volatile
.
Кто прав?
Это было изнурительно. Здесь, конечно, много места для интерпретации, в зависимости от того, какие документы вы прочитали, а что нет, и как вы выбираете интерпретировать множество слов, которые недостаточно специфичны. Кажется очевидным, что что-то не так: либо
- Обоснование и N1381 ошибочно или беспорядочно сформулированы или
- они были специально аннулированы ретроактивно... или
- Стандарт ошибочно или беспорядочно сформулирован.
Надеюсь, что мы сможем добиться большего, чем всякая двусмысленность и предположения, которые, кажется, окружали это в прошлом, и получить более убедительное выражение, поставленное на запись. С этой целью любые дополнительные источники и мысли от экспертов были бы очень желанными.