Обеспечивает ли доступ к объявленному энергонезависимому объекту через энергозависимую ссылку / указатель энергозависимые правила при указанных доступах?

Это будет длинный вопрос, так как для контекстуализации и предоставления как можно большего количества информации я должен извлекать различные ссылки и цитаты - что часто является единственным способом, как только мы входим в C / C ++ Standard Rabbit Hole. Если у вас есть лучшие цитаты или какие-либо другие улучшения этого поста, пожалуйста, дайте мне знать. Но, чтобы подвести итог заранее,Вы можете обвинить @zwol для меня это сообщение ;-) и цель состоит в том, чтобы найти истину из двух положений:

Выполните C и (путем импорта; см. Комментарии) Стандарты C ++ требуют, чтобы доступ осуществлялся черезvolatile * или жеvolatile & должен ссылаться на объект, первоначально объявленныйvolatile чтобы иметьvolatile семантика?Или жеполучает доступ кvolatileквалифицированный объект черезvolatile указатель / ссылка достаточны / должны заставить эти обращения вести себя так, как если бы объект был объявленvolatile?

И так или иначе, если (как кажется) формулировка несколько двусмысленна по сравнению с намерением -мы можем получить это ясно в самих стандартах?

Первая из этих взаимоисключающих интерпретаций чаще встречается, и это не совсем безосновательно. Тем не менее, я надеюсь показать, что есть существенное количество «разумных сомнений» в пользу 2-го, особенно когда мы вернемся к некоторым предыдущим отрывкам в «Обосновании» и «РГ».


Принятая мудрость: упомянутый объект должен быть объявленvolatile

Вчерашний популярный вопросЯвляется ли определение «изменчивым» таким изменчивым, или GCC имеет некоторые стандартные проблемы соответствия? возникла, предполагаяvolatile ссылка дастvolatile поведение на неvolatile референт - но обнаружил, что это не так, или сделал в различной степени и непредсказуемым образом.

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

Ключевое слово в этом отрывке - объект.volatile sig_atomic_t flag; это изменчивый объект.*(volatile char *)foo это простодоступ через изменчивую квалификацию lvalue и стандарт не требует, чтобы он имел какие-либо специальные эффекты, -zwol

Такое толкование, по-видимому, довольно широко распространено, как видно из ответов на этот похожий, но, надеюсь, не дублирующий вопрос:Требования к поведению указателя на volatile, указывающего на энергонезависимый объект Но даже там есть неопределенность: сразу после ответа «нет», затем «возможно»! В любом случае ... давайте проверим Стандарт, чтобы увидеть, на чем основаны «нет».


Что стандарт говорит ... или нет

C11,N1548, §6.7.3: Понятно, что это UB для доступа к объектуопределяется с volatile или жеconst введите через указатель, который не разделяет указанный классификатор ...

6 Если сделана попытка изменить объект, определенный сconstквалифицированный тип посредством использования lvalue сconst-квалифицированный тип, поведение не определено. Если сделана попытка обратиться кобъект, определенный сvolatileквалифицированный тип через использование lvalue сvolatile-квалифицированный тип, поведение не определено. (133)

... Стандарт, кажется, не упоминает прямо противоположный сценарий, а именноvolatile, Более того, при подведенииvolatile и операции на нем, теперь он говорит об объекте, которыйимеет volatile-квалифицированный тип:

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

Должны ли мы предполагать, что «имеет» эквивалентно «был определен с»? или жеможет "имеет" ссылаетесь на комбинацию объектных и ссылочных классификаторов?

Комментатор суммировал проблему с такой формулировкой:

Отn1548 §6.7.3 the6 стандарт использует фразу «объект, определенный с типом с изменяемой спецификацией», чтобы отличить его от «lvalue с типом с квалифицированной спецификацией». К сожалению, этот «объект, определенный с различием» по сравнению с «lvalue», не переносится, и стандарт затем использует «объект, имеющий тип, определяемый volatile», и говорит, что «то, что составляет доступ к объекту, который имеет тип, определяемый volatile» определяется реализацией "(которая могла бы сказать" lvalue "или" объект, определенный с "для ясности). Ну что ж. -Дитрих Эпп

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


Разумное сомнение: Есть / Былvolatile указатель / ссылка предназначена для присвоенияvolatile семантика на ее разыменование?

Вышеупомянутый ответ содержит комментарий, в котором автор цитирует более раннее заявление Комитета, в котором ставится под сомнение идея «ссылка должна соответствовать референту»:

Интересно, что там есть одно предложение [Обоснование C99 дляvolatile] это означает, что комитетозначало за*(volatile T*)x заставить этот доступ кx быть обращенным как изменчивый; но фактическая формулировка стандарта не достигает этого. - Звол

Мы можем найти немного больше информации об этом бите Обоснования, из 2-го вышеупомянутого потока:Требования к поведению указателя на volatile, указывающего на энергонезависимый объект

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

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

philipxy

И изэтот поток байтовмы упоминаем C99 s6.7.3 p3 - a.k.a. C11's p4 - и этот анализ:

Данный абзац находится непосредственно перед разделом 6.7.3.1 в обосновании документа. Если вам также нужно привести цитату из самого стандартного документа, приведите6.7.3 р3:

Свойства, связанные с квалифицированными типами, имеют смысл только для выражений, которые являются lvalues.

Выражение(volatile WHATEVER) non_volatile_object_identifier являетсяне lvalue, следовательно, термин «volatile» не имеет смысла.

И наоборот, выражение* (volatile WHATEVER *) & non_volatile_object_identifier является lvalue (он может быть размещен слева от оператора присваивания), поэтому свойство квалификатора 'volatile' имеет в этом случае предполагаемое значение.

Тим Рентш

Eстьочень конкретная демонстрация в поддержку этой идеи, с особым учетом 1-го связанного вопроса, вWG PaperN1381, Это введено в приложениеmemset_s() делать то, что хотел этот ОП - гарантировать незаполненное заполнение памяти. При обсуждении возможных реализаций, кажется, поддерживается идея - без указания какого-либо требования - что использованиеvolatile указатель, чтобы изменить не-volatile объектдолжен генерировать код на основеклассификатор указателянезависимо от того, что из упомянутого объекта ...

Независимое от платформы решение «secure-memset»:
void *secure_memset(void *v, int c , size_t n) {
    volatile unsigned char *p = v;
    while (n--) *p++ = c;
    return v;
}

Такой подход предотвратит очистку памяти от оптимизации ион должен работать на любой стандартной платформе.

... и что компиляторы этого не делают

Там было недавнее уведомление о том, чтонекоторые компиляторы нарушают стандарт, не всегда соблюдаяvolatile Классификатор.


Кто прав?

Это было утомительно. Здесь, безусловно, есть много возможностей для интерпретации, в зависимости от того, какие документы вы прочитали, а какие нет, и от того, как вы решили интерпретировать много слов, которые недостаточно конкретны. Кажется очевидным, что что-то не так: либо:

Обоснование и N1381 неверно или случайно сформулированы, илиони были специально признаны недействительными задним числом ... илиСтандарт неверно или случайно сформулирован.

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

 underscore_d07 июл. 2016 г., 15:16
@Lundin Спасибо - легкое чтение перед сном ... с первого взгляда, какой беспорядок! Интересно, нашли ли они когда-нибудь это:stackoverflow.com/questions/38235112/...
 supercat08 июл. 2016 г., 03:16
... локальные операции чтения / записи и физическая память не являются проблемой компилятора, но компилятор не должен вторично угадывать программисту, является лиvolatile чтение или запись должны быть оформлены. Лично я думаю, что C будет значительно улучшен с помощью «полулетучего» квалификатора, который обеспечит упорядочение логических операций чтения и записи в отношении «volatile», но не в отношении других «полулетучих» переменных.
 David Schwartz07 июл. 2016 г., 23:23
@supercat Ничего не зная об этих механизмах, они не могли знать, каковы их требования. Так что, если случится сделать то, что требуют эти механизмы, это будет просто по счастливой случайности. (По правде говоря, авторы компиляторов имеют подробные знания о требованиях разработчиков систем к платформам, которые они поддерживают. Без этого они ошиблись бы так же часто, как и поняли. Конечно, иногда они все же ошибаются.)
 knivil07 июл. 2016 г., 13:24
volatile в основном означает иметь дело с необычной памятью. Как компилятор должен выбирать между необычной памятью и обычной памятью, основываясь на типе / значении указателя.
 underscore_d07 июл. 2016 г., 14:01
@ N.m. Я включил это специально, потому что это оченьне необычно, скорее к сожалению распространено. Однако цинизм не слишком далеко продвинет нас! Как уже говорилось, мне нравится думать, что мы можем добиться большего успеха. Многочисленные прошлые ДР и тому подобное свидетельствуют об этом.
 philipxy20 февр. 2017 г., 03:41
См. Мой ответ, в котором рассматривается отчет о дефекте языка Си относительно языка стандарта Си против намерения.
 underscore_d07 июл. 2016 г., 13:07
@ downvoters: давай, помоги мне здесь.
 Johannes Schaub - litb07 июл. 2016 г., 14:56
Не будучи экспертом здесь, но «изменчивая семантика», как описано в спецификации C ++, имеет несколько граней. Доступ с изменчивыми l-значениями (не обязательно с изменчивыми объектами) всегдапобочный эффект, И другая сторона заключается в том, что только если у вас есть изменчивый объект (использование изменяемого lvalue для доступа недостаточно), операции, которые вы над ним выполняете,наблюдаемые побочные эффекты.
 underscore_d07 июл. 2016 г., 16:10
@RichardHodges Я удалил свой ответ, чтобы переместить его в другое место, думая, что ваш комментарий был удален ... Снова:Ваш комментарий поднимает очень интересный вопрос и это именно то, что я ищу. Именно такие вещи заставляют меня, как и большинство, склоняться к интерпретации, которую ссылки не имеют права предоставлятьvolatileность. Но намерение, что онибыло бы было четко указано в нескольких предыдущих документах. Итак, опять же, окончательная цитата из Стандарта - или исправление его - является целью. Я лично не против, какая интерпретация правильна. Я просто хочу знать, что это такое.
 Lundin07 июл. 2016 г., 14:54
Вы можете найтиЭта статья интересно.
 philipxy12 июл. 2016 г., 21:59
Я думаю, что важно показать цитату gnu.org, которую я вставил в свой ответ, показывающую мнение крупного проекта компилятора о том, что«из стандарта неясно, обеспечивают ли изменчивые l-значения в целом больше гарантий, чем нелетучих l-значений, если базовые объекты являются обычными». PS Отличный пост. Хотя я думаю, что это на самом деле другоеответ на вопрос, который, я надеюсь, не будет повторяться », - ответил я. Но какова связь между вопросами и ответами, кажется столь же неясной, как и их окончательный ответ!
 underscore_d07 июл. 2016 г., 14:00
@knivil Хороший вопрос. Существуют очень веские аргументы в пользу того, что ссылка не может изменить семантику своего референта. Но есть очень веские аргументы против различных вещей, которыеявляются однозначно указано и в Стандарте! Я спрашиваю, каково намерение и правильно ли отражает стандарт намерение, а не плюсы и минусы в любом случае.
 supercat08 июл. 2016 г., 01:08
@DavidSchwartz: Что вы имеете в виду «вряд ли будет то, что хочет программист»? По какой другой причине программист может использоватьvolatile Классификатор?
 supercat08 июл. 2016 г., 04:44
@DavidSchwartz: в любом случае ключевой момент заключается в том, что программист, вероятно, будет знать больше о том, что требуется, чем компилятор; если программисту нужны некоторые, но не все операции над объектом, упорядоченные по отношению к другим изменчивым операциям, имеющим честь компилятораvolatile сделает это возможным. Если такое упорядочение будет бесполезно и неприемлемо ухудшать производительность, программист может использовать неквалифицированный указатель. Однако, если компилятор не соблюдает такой порядок и это оказывается необходимым, возможно, не существует эффективного способа получить необходимую семантику.
 David Schwartz08 июл. 2016 г., 04:17
@supercat Вы можете сказать, что вы думаетеvolatile следует делать исходя из того, что сделало бы его полезным для людей на определенных платформах. Только не делайте вид, что это то, что говорит стандарт. И не говорите, что это должен быть «порядок, в котором процессор загружает и хранит», как если бы это было не для платформы. (На самом деле, вы даже не можете определить, что означает «выдавать» нагрузку или хранилище без ссылки на конкретное оборудование, поскольку граница между процессором и памятью является гибкой, а не жесткой линией, как в абстрактной машине.)
 David Schwartz08 июл. 2016 г., 02:25
@supercat Для связи с оборудованием. Для синхронизации между потоками. И много других вещей, которые не чувствительны к порядку записи в памяти. (Либо потому, что они вообще не задействуют память, либо потому, что они обращаются к памяти только через аппаратное обеспечение когерентности кэша.) Что эти вещи чувствительны к порядку, в котором операции идут в память, или что барьеры памяти фактически влияют на операции с памятью на типичных аппаратное обеспечение, это распространенный миф. Но это все зависит от платформы, конечно.
 n.m.07 июл. 2016 г., 13:29
"неправильно или случайно сформулировано" - это что-то необычное? Цвет меня циничный.
 Richard Hodges07 июл. 2016 г., 13:00
Я предполагаю, что основной вопрос «насколько абстрактной мы ожидаем модель памяти?». Определив указатель non-vol как volatile, мы, похоже, просим компилятор «напрямую записывать в память ввода-вывода». Это нормально, но если компилятор ранее определил, что «память» не должна существовать, что он должен делать? Возврат и создание памяти, или игнорировать вас?
 Johannes Schaub - litb07 июл. 2016 г., 15:01
Таким образом, даже чтение через изменчивое l-значение представляет собой побочный эффект (не обязательно наблюдаемый, то есть может быть оптимизирован), в то время как то же самое не относится к энергонезависимым l-значениям. Таким образом, вы не можете иметь два чтения volatilr lvalus одного и того же объекта без упорядочения между ними, но это не означает, что побочные эффекты являются наблюдаемыми, если вы не имеете дело с реальными изменчивыми объектами (по крайней мере, с C ++ 11, не знать о C ++ 14!)
 supercat07 июл. 2016 г., 23:16
@DavidSchwartz: для того, чтобы компилятор был полезен для системного программирования, если только одна и та же сущность не управляет компилятором и платформой выполнения, разработчик компилятора должен предположить, что программист может знать о платформе выполнения то, чего не знает компилятор. Стандарт не требует, чтобы совместимые реализации были подходящими для системного программирования, но на большинстве платформ любой компилятор, который подходит для системного программирования, должен предполагать, что любой изменчивый доступ может быть "наблюдаемым" механизмами, о которых он ничего не знает.
 supercat08 июл. 2016 г., 03:14
@DavidSchwartz: доступ к аппаратному обеспечению и синхронизация потоков могут показаться чувствительными к порядку, в котором процессор загружает и сохраняет данные. Я не уверен, что будет «много других вещей», которые не чувствительны к загрузке / упорядочению магазина. Требуются ли другие действия перед загрузкой или после того, как будут созданы хранилища, обычно зависит от конфигурации оборудования, которая часто будет известна программисту, но не автору компилятора. Если это не было ясно, я говорю, чтоvolatile должен убедиться, что процессор выдает записи и чтения, как указано; что происходит между ...
 supercat08 июл. 2016 г., 00:43
@DavidSchwartz: Кроме того, если не была запрошена более слабая семантика, компилятор должен обеспечить синхронизацию всех значений в кэше регистров, чей адрес был открыт внешнему миру, до и после любогоvolatile доступ. Хотя это не всегда необходимо, это безопасное значение по умолчанию. Компилятор, который хочет обеспечить более эффективную генерацию кода, может предложить способ отказаться от такой семантики, когда они не нужны. Я не уверен, что сложно в этом.
 David Schwartz08 июл. 2016 г., 00:55
@supercat Не думаю, что в этом есть какой-то смысл. Зачем компилятору делать это, если это не то, что требует стандарт, и вряд ли это то, чего хочет программист? Какая возможная причина может быть? Единственными вероятными причинами является то, что этого требует стандарт, или что у нас есть знания, специфичные для платформы, которые полезны. (И ни один компилятор, который я знаю, заставляет такую ​​синхронизацию с памятью на x86. Это почтиникогда необходимо, и это нелепо дорого. Стандарт не требует этого. Это не полезно. Зачем это делать?)
 David Schwartz07 июл. 2016 г., 22:38
@Lundin Многие пункты этой статьи верны. Но многие из них являются законными вариантами реализации, которые неверно истолковываются как нарушения стандартов, поскольку они делают неверное и неподдерживаемое предположение, что когда стандарт говорит о наблюдаемых доступах, это означает, что в потоке команд. Нет никаких оснований для этого предположения - поток команд является внутренней деталью реализации. Стандарт говорит о том, что должна делать система, а не о том, какие инструкции нужно использовать для того, чтобы дать команду делать что-то.
 supercat08 июл. 2016 г., 04:38
@DavidSchwartz: Под «заказом» я подразумеваю логический порядок, в котором загрузка и сохранение выполняются в коде, который находится под контролем компилятора. То, как это приводит к физическому упорядочению, часто зависит от факторов, которые могут находиться вне контроля компилятора, но могут или не могут находиться вне контроля программиста. Если программист выполняетvolatile хранит в определенной последовательности, компилятор должен генерировать код, который выполняет эти операции в той же логической последовательности.
 supercat08 июл. 2016 г., 00:36
@DavidSchwartz: на большинстве платформ будет очевидно, как компилятор может удовлетворить ожидания программиста. Если процессор имеет 32-битную инструкцию сохранения, тогдаuint32_t volatile *p;, эффект*p=0x12345678; следует использовать 32-разрядное хранилище для записи 0x12345678 по адресу, указанномуp, Если программист пишет+*p; как утверждение, компилятор должен использовать 32-битную загрузку для чтения с адреса, указанногоp и игнорировать результат. Компилятору не должно быть никакого дела, почему программист захочет делать такие вещи - он должен просто делать это.

Ответы на вопрос(4)

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

Стандарт классифицирует семантикуvolatile доступы определяются в соответствии с реализацией, и никоим образом, ни форма, ни форма не требуют, чтобы реализация определяла их с пользой. Таким образом, было бы неразумным утверждать, что при условии документированного и фактического поведения, реализацияvolatile семантика, подобная gcc, сделает реализацию несовместимой, но просто сделает ее бесполезной для целей, для которых она могла бы быть подходящей.

Обратите внимание, что gcc часто используется на платформах, где возможно сконфигурировать произвольную область адресного пространства, которая ведет себя как устройство ввода-вывода, а затем ведет себя как обычная RAM. Таким образом, может быть необходимо убедиться, что определенные операции очень точно упорядочены, даже если последовательность большинства других операций не имеет значения; требующий, чтобы все операции с чем-либо рассматривались какvolatile для того, чтобы какие-либо операции обрабатывались таким образом, не кажется хорошим рецептом для оптимизации.

Что я нахожу странным, так это то, что за последние несколько лет люди стали настолько заинтересованы в том, позволяет ли Стандарт компиляторам реализовывать бесполезную семантику для некоторых конструкций, с целью повышения производительности кода, который не требует, чтобы конструкции были полезными, когда такие подход, по-видимому, почти во всех отношениях уступает реализации полезной семантики по умолчанию, но предоставляет программистам, которым не нужна такая семантика, отказываться от них, используя ключи командной строки или директивы #pragma. Если программа включает в себя [гипотетический]#pragma gcc_loose_volatile директива, gcc может делать все, что угодно, независимо от того, как иначе можно интерпретировать требования Стандарта относительноvolatileи если в нем нет такой директивы, бесполезная семантика будет бесполезной независимо от того, запрещает ли Стандарт их или нет.

 supercat08 июл. 2016 г., 01:55
... будет рассматривать цельvolatileквалифицированный указатель как volatile, отсутствующие директивы или параметры компилятора, разрешающие ему делать иначе. То, что gcc этого не делает, делает его плохим компилятором для использования на любой платформе, где можно использовать асинхронные события.
 supercat08 июл. 2016 г., 01:53
@underscore_d: Я не знаю ничего в Стандарте, которое могло бы сделать поведение gcc здесь несоответствующим. Действительно, на платформах, которые не определяют какие-либо средства, с помощью которых могут возникать асинхронные сигналы, у Стандарта не было бы веских оснований запрещать такое поведение. Авторы Стандарта очень редко говорят, что определенные поведения должны быть определены на некоторых платформах, но не должны быть определены на других; они более склонны полагаться на суждения разработчиков о том, какое поведение должна поддерживать любая конкретная платформа. Любой хороший компилятор для платформы с асинхронными событиями ...
 underscore_d07 июл. 2016 г., 22:52
Но мой вопрос не в том, что является допустимым поведением, определяемым реализацией дляvolatile доступы, учитывая, что, конечно, в основном все, что есть. Речь идет о том, какие операции считаютсяvolatile доступы - конкретно лиvolatileКвалифицированные указатели / ссылки могут считаться предоставленными или не предоставленнымиvolatile поведение по отношению к указанному объекту, не объявленномуvolatile, Я не знаю, как я могу сделать это яснее.

потому что я думаю, что вдумчивый не ответ может помочь раскрыть здесь истину.

Я предполагаю, что основной вопрос «насколько абстрактной мы ожидаем модель памяти?». Определив указатель non-vol как volatile, мы, похоже, просим компилятор «напрямую записывать данные в память ввода-вывода». Это нормально, но если компилятор ранее определил, что «память» не должна существовать, что он должен делать? Возврат и создание памяти, или игнорировать вас?

Мне кажется, что следующие два случая очень разные по своему намерению:

Отображение в память ввода-вывода

volatile unsigned char * const uart_base = (volatile unsigned char *)0x10000;

Это явно предназначено для информирования компилятора о том, что UART отображен в память по адресу 0x10000.

Стирание пароля, хэшей
void *secure_memset(void *v, int c , size_t n) {
    volatile unsigned char *p = v;
    while (n--) *p++ = c;
    return v;
} 

Это явно предназначено для того, чтобы гарантировать, что память в v to (int *) v + n действительно модифицируется перед возвратом функции.

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

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

Благодарю. Поскольку адрес взят, разве объект не должен занимать память?

GCC, похоже, согласен с вами:

#include <cstdint>
#include <cstring>

void * clearmem(void* p, std::size_t len)
{
  auto vp = reinterpret_cast<volatile char*>(p);
  while (len--) {
    *vp++ = 0;
  }
  return p;
}

struct A
{
  char sensitive[100];

  A(const char* p)
  {
    std::strcpy(sensitive, p);
  }

  ~A() {
    clearmem(&sensitive[0], 100);
  }
};

void use_privacy(A a)
{
  auto b = a;
}


int main()
{
  A a("very private");
  use_privacy(a);
}

выходы:

clearmem(void*, unsigned long):
        leaq    (%rdi,%rsi), %rax
        testq   %rsi, %rsi
        je      .L4
.L5:
        movb    $0, (%rdi)
        addq    $1, %rdi
        cmpq    %rax, %rdi
        jne     .L5
.L4:
        xorl    %eax, %eax
        ret
use_privacy(A):
        leaq    -120(%rsp), %rax
        leaq    100(%rax), %rdx
.L10:
        movb    $0, (%rax)
        addq    $1, %rax
        cmpq    %rdx, %rax
        jne     .L10
        ret
main:
        leaq    -120(%rsp), %rax
        leaq    100(%rax), %rdx
.L13:
        movb    $0, (%rax)
        addq    $1, %rax
        cmpq    %rdx, %rax
        jne     .L13
        leaq    -120(%rsp), %rax
        leaq    100(%rax), %rdx
.L14:
        movb    $0, (%rax)
        addq    $1, %rax
        cmpq    %rdx, %rax
        jne     .L14
        leaq    -120(%rsp), %rax
        leaq    100(%rax), %rdx
.L15:
        movb    $0, (%rax)
        addq    $1, %rax
        cmpq    %rdx, %rax
        jne     .L15
        xorl    %eax, %eax
        ret

Clang не исключает создание частных массивов, поэтому я не могу сделать там никаких выводов.

 supercat11 июл. 2016 г., 16:18
... «выборочное соответствие» должно сделать практичным написание программ, которые могут быть гарантированно либо работать правильно, либо не работатьопределенным образом на любой совместимой платформе.
 underscore_d08 июл. 2016 г., 11:41
@supercat Конечно, я не вижу никаких трудностей. Вот почему я думаю, что компиляторы должны это делать, а Стандарт должен делать их! Но это, кажется, не обеспечивает это или указывает, что происходит при использованииvolatile ссылка на неvolatile объект (только обратное).
 supercat08 июл. 2016 г., 01:22
@underscore_d: Когда дерево выражений, содержащее оператор присваивания, анализируется, компилятор должен знать, что операнд унарного* этоvolatileуказатель, и, таким образом, левый операнд оператора присваивания такжеvolatile-qualified. В этот момент казалось бы простым распознать «назначить volatile lvalue» как операцию, эквивалентную вышеупомянутому вызову функции, который позаботился бы о подавлении оптимизации независимо от того, откуда поступил адрес.
 Richard Hodges07 июл. 2016 г., 13:35
@underscore_d Если это так, то clang нарушает множество правил, когда (не) копирует массивы constexpr.
 Richard Hodges07 июл. 2016 г., 16:13
@underscore_d -O3
 Richard Hodges07 июл. 2016 г., 13:49
@underscore_d обновил ответ несколькими тестами. и gcc, и clang обнуляют память. GCC удаляет все копии символьных данных. лязг нет.
 underscore_d07 июл. 2016 г., 13:32
Благодарю. Поскольку адрес взят, разве объект не должен занимать память?
 underscore_d07 июл. 2016 г., 13:56
Очень интересно. Но какой уровень оптимизации вы использовали? В любом случае, возможно, компилятор анализирует тело функции и использует его для исключениякак будто оптимизация, когда он может видеть, что переданный адрес приведен кvolatile ссылка. Это будет означать, что мой предыдущий комментарий не будет применяться к таким случаям. Опять же, это имеет смысл, но может быть очень трудно отследить и / или помешать другим оптимизациям. Уму непостижимо
 supercat08 июл. 2016 г., 18:09
@underscore_d: Стандарт обычно маркирует поведение как определяемое реализацией только в том случае, если нет правдоподобной ситуации или реализации, в которой требование реализаций для фиксации определенного поведения сделало бы язык менее полезным, если только это не привело бы к тому, что язык стал бы более полезным даже в таких случаях. платформ. Что необходимо, так это категория поведения, в которой реализациям будет настоятельно рекомендоваться совершать выбор вариантов поведения, когда это целесообразно, и потребуется документально подтвердить отказ от каких-либо обязательств в тех случаях, когда это будет нецелесообразно.
 Richard Hodges08 июл. 2016 г., 18:01
@underscore_d после прочтения сообщения суперкатера мне приходит в голову, что может быть какая-то архитектура или платформа, где концепция ввода-вывода с отображением в память не имеет смысла. В такой архитектуре генератор кода мог бы полностью игнорировать ключевое слово volatile, поскольку volatile не имеет никакого значения, кроме этого (например, оно не заставляет последовательность записи в память последовательно выполняться между потоками, поэтому правило «как если») Конечно, может вступить в игру WRT интерпретация летучих записей в той же теме).
 underscore_d08 июл. 2016 г., 18:19
@supercat Если так, то это еще один нюанс бесконечной неопределенности Стандарта, который я еще не усвоил! Что касается новой категории, хорошая идея. Известны ли вам какие-либо попытки ввести такие новые категории или иным образом улучшить способность стандарта более четко заявить о себе и расширить возможности авторов и пользователей компиляторов, которые хотят большей гибкости в таких ситуациях? В любом случае, вам понадобится быстрое, но совершенно не интуитивное имя для этого ...реализации, запрещающие? Я не знаю.
 supercat11 июл. 2016 г., 16:09
@underscore_d: Моя мысль состояла в том, чтобы определить «Testible Constrained Behavior», где реализации потребуются для определения макросов, которые программы могут использовать для тестирования поддерживаемых гарантий или утверждения требований, так что реализации, которые не могут их поддерживать, потребуются для отказа от компиляции, и «тестируемое поведение», которое было бы аналогичным, но для вещей, которые в настоящее время определяются реализацией. Я также хотел бы увидеть концепцию «избирательно согласующейся» программы, которую не нужно было бы строить на каждой платформе, но которая должна была бы гарантировать правильность ...
 underscore_d08 июл. 2016 г., 17:43
@supercat Поверьте мне, я понимаю вашу точку зрения, которая была сделана с большим повторением. Моя точка зрения заключается в том, что полное отсутствие указания на то, что должно происходить, отличается от явного указания того, что оно определяется реализацией или UB. Вы продолжаете говорить о последнем, но Стандарт, кажется, сделал первое. Насколько я могу видеть, Стандарт квалифицировал только как «определенные реализацией» операции над неопределенно определенным «объектом, который имеет изменчивый тип», но не указывает, включает ли он указатели / ссылки на них или, в любом случае, что должно произойти к тем.
 supercat08 июл. 2016 г., 01:14
@underscore_d: Я не уверен, что вижу сложность исключения оптимизаций при записи в изменчивую ссылку. С точки зрения оптимизатора, учитываяvolatile uint32_t *p; код*p=6; следует рассматривать как вызов непрозрачной функцииvolatile_write32(p,6); пока не пришло время фактически сгенерировать код, после чего сгенерированная инструкция должна быть 32-битным хранилищем.
 supercat08 июл. 2016 г., 17:41
@underscore_d: Философия авторов Стандарта заключается в том, что, если могут существовать реализации и обстоятельства, в которых С может оказаться более полезным, если Стандарту не требуется, чтобы они что-то сделали, Стандарту следует предписывать поведение только в этом случае. в итоге сделает язык более полезнымдаже на этих реализациях, Так как Стандарт никогда не предназначался для интерпретации как набора требований, которым программисты должны следовать даже на платформах, где их наложение не принесло бы никакой полезной цели, не было «бремени доказательства» для создания чего-то UB.
 supercat11 июл. 2016 г., 16:14
... работа на каждой платформе, где она собирается. В настоящее время Стандарт определяет только две категории программ: «соответствующую» программу, которая не нарушает ограничений и по крайней мере имеет платформу, на которой он будет работать, и «строго соответствующую» программу, которая остается ниже рекомендуемых пределов реализации, и будет работать на любой совместимой платформе, где она не выходит из строя по причине ограничений реализации. Стандарт в настоящее время не пытается гарантировать, что любая программа не выйдет из строя произвольно на любой платформе, но добавляет концепцию ...

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

 underscore_d07 июл. 2016 г., 23:12
@supercat True, but again, that only speaks to what some implementation considers defined, not the Standard. I'm only asking about the latter. Your concerns about implementations defining counterintuitive and/or useless things are valid, but I'm not sure they're really relevant.
 David Schwartz07 июл. 2016 г., 23:06
@supercat I agree, but that's not a standards violation. That's a usability complaint.
 David Schwartz07 июл. 2016 г., 22:51
@underscore_d Sometimes the best solution is just to avoid trying to language lawyer and just build tools that do what people want them to do. If someone accesses a non-volatile object through a volatile-qualified type, a sensible compiler should do what a typical person familiar with the standard would be most likely to want on that platform.
 supercat08 июл. 2016 г., 18:15
@DavidSchwartz: If a compiler required fifty petabytes of stack space to execute any function whose source text contained the letter "z" and behaved arbitrarily if such space was unavailable, would that be a standards violation or a usability complaint? Under the as-if rule, if a compiler writer that knew there would never be fifty petabytes of stack available simply generated arbitrary code for any function containing the letter "z", would that be a standards violation or a usability complaint? Provided a compiler outputs required diagnostics for ill-formed programs...
 supercat07 июл. 2016 г., 23:07
@underscore_d: With regard to what counts as a "volatile" access, btw, I'd say that if an implementation documents that accesses which are not traceable to objects that lack volatile qualifiers have one effect, and those which are traceable to such objects have another, such behavior may be indistinguishable from that of treating the latter accesses as though they were not volatile qualified, but would still be Standards-compliant.
 David Schwartz07 июл. 2016 г., 22:59
@supercat And I would say the only portable use of volatile is with signals.
 supercat07 июл. 2016 г., 23:38
@underscore_d: Except on platforms where it would be impossible to observe the effects of "volatile", the indicated behavior is either compliant but useless, or non-compliant and useless. This is one of many "holes" in the Standard where implementations aren't required to behave usefully, but quality implementations will do so anyway.
 underscore_d07 июл. 2016 г., 22:45
@DavidSchwartz Вы, скорее всего, правы на практике. Но строка звучит так: «То, что составляет доступ к объекту с типом с изменяемой спецификацией, определяется реализацией», и мой вопрос заключается в том, предназначен ли «объект с типом с квалифицированной спецификацией», чтобы разрешить указанную квалификацию при доступе. через указатель с такой квалификацией, или означает ли это просто объект, первоначально объявленныйvolatile«... и если последнее, то почему они просто так не говорят. Попытка интерпретировать Стандарты - нелепая задача. У меня нет ничего, кроме уважения к тем, кому удается построить целые компиляторы на этом беспорядке
 underscore_d07 июл. 2016 г., 20:04
Итак, это да или нет на вопрос в названии? Вопрос в томкакие «правильно»: еслиvolatile ссылка производит код в соответствии с объявлением референта, или если он производит код, как если бы референт был объявленvolatile?
 supercat07 июл. 2016 г., 23:02
@DavidSchwartz: C is widely used in embedded systems. Code which interacts with a particular kind of I/O device will obviously only work with devices that behave similarly, but if there are two or more compilers for the same hardware platform [for most platforms there are at least three] there's no good reason code shouldn't be readily portable among them. On most hardware platforms it's pretty clear what volatile should mean, and gcc does not honor the meaning for the hardware platforms it targets.
 David Schwartz07 июл. 2016 г., 22:35
@underscore_d Ни одно из этих действий не запрещено стандартом. Таким образом, переносимый код не может полагаться ни на что. Компиляторы могут свободно документировать свое поведение, чтобы на него мог положиться специфичный для платформы код.
 supercat07 июл. 2016 г., 22:52
@DavidSchwartz: A sufficiently obtuse implementation can be guaranteed to break almost any program, no matter how portable it tries to be. I would suggest that code which relies upon volatile to be implemented in non-obtuse fashion should be considered portable to non-obtuse implementations.
 supercat08 июл. 2016 г., 18:17
...and has sufficient documentation for all "implementation-defined" behaviors, I can't think of any standards violation that couldn't be called a "usability constraint" under the As-If Rule and One Program Rule.
Решение Вопроса

энергозависимую ссылку / указатель энергозависимые правила при указанных доступах?

volatile не означает то же самое в C & C ++. Стандарт C ++ делает доступными через изменчивые l-значения наблюдаемые. [1] Он говорит, что намерен быть таким же, как поведение C. И это поведение, описанное в Обосновании C. Тем не менее, в стандарте C говорится, что доступ к объектам, объявленным volatile, является наблюдаемым. (Обратите внимание, что доступ к объекту, объявленному volatile через энергонезависимое lvalue, не определен.)

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

Сводка по отчету о неисправностях для C11 версии 1.10 Дата: апрель 2016 г.DR 476 изменчивая семантика для lvalues ​​04/2016 Open

Конечно, то, что делается с наблюдаемым поведением, зависит от реализации.

Там действительно нет никакой двусмысленности. Просто людине могу поверить что поведение стандарта C может быть тем, чем оно является, потому что это не историческоеvolatile (когда буквально-адресные lvalues ​​считались изменчивыми объектами), как предполагалось в Обосновании, как реализовано компиляторами до и с тех пор, как интерпретируется и описывается Стандартом C ++, как исправлено в DR. Точно так же стандарт ясен в том, что он не говорит о том, что энергонезависимый доступ является наблюдаемым, поэтому это не так. (И «побочный эффект» - это термин, используемый при определении частичного порядка оценки.)

[1] Или, по крайней мере, надеюсь, что теперь. Из комментария отunderscore_d:

Для C ++, см. ТакжеP0612R0: Примечание NB CH 2: изменчивый, которыйбыл принят в этом месяце убрать остатки разговоров о "изменчивых объектах" в стандарте C ++, когда это действительнодоступ через изменчивые glvalues это то, что он имел в виду (как, предположительно / надеюсь, что имел в виду C).

 philipxy28 мар. 2017 г., 02:24
Я отредактировал ваш последний комментарий как сноску в моем ответе.
 underscore_d20 февр. 2017 г., 11:51
Отлично! Спасибо. Я не проверял, отличается ли C ++, и особенно не знал, что DR для C. Я думаю, что это самый точный ответ на этот вопрос. Я буду следить за результатами этого DR.
 underscore_d24 мар. 2017 г., 23:00
Для C ++, см. ТакжеP0612R0: Примечание NB CH 2: изменчивый, которыйбыл принят в этом месяце убрать остатки разговоров о "изменчивых объектах" в стандарте C ++, когда это действительнодоступ через изменчивые glvalues это то, что он имел в виду (как, предположительно / надеюсь, что имел в виду C).

Ваш ответ на вопрос