Псевдоним строгого указателя: является ли доступ через «изменчивый» указатель/ссылку решением?

По пятам конкретной проблемы, самостоятельный ответ и комментарии к нему, я хотел бы понять, является ли это правильным решением, обходным путем/взломом или просто неправильным.

В частности, я переписал код:

T x = ...;
if (*reinterpret_cast <int*> (&x) == 0)
  ...

As:

T x = ...;
if (*reinterpret_cast <volatile int*> (&x) == 0)
  ...

с квалификатором volatile к указателю.

Давайте просто предположим, что обращение с T как с int в моей ситуации имеет смысл. Решает ли этот доступ через ссылку volatile проблему псевдонима указателя?

Для справки, из спецификации:

[Примечание: volatile — это подсказка реализации, чтобы избежать агрессивной оптимизации с участием объекта, поскольку значение объекта может быть изменено средствами, не обнаруживаемыми реализацией. Подробную семантику см. в 1.9. В общем, семантика volatile должна быть такой же в C++, как и в C. — примечание в конце]

РЕДАКТИРОВАТЬ:

Приведенный выше код действительно решил мою проблему, по крайней мере, на GCC 4.5.


person doublep    schedule 05.06.2010    source источник
comment
Этот вопрос не явно специфичен для C++. Приведения типов в стиле C++ можно тривиально переписать на C.   -  person curiousguy    schedule 07.04.2013
comment
Однако @curiousguy C и C++ имеют разные языковые правила.   -  person M.M    schedule 02.05.2015
comment
@MattMcNabb Чем отличаются WRT volatile?   -  person curiousguy    schedule 02.05.2015


Ответы (2)


Volatile не может помочь вам избежать неопределенного поведения здесь. Так что, если это работает для вас с GCC, это удача.

Предположим, что T — это POD. Тогда правильный способ сделать это

T x = …;
int i;
memcpy(&i,&x,sizeof i);
if (i==0)
  …

Там! Нет проблем со строгим псевдонимом и проблем с выравниванием памяти. GCC даже обрабатывает memcpy как встроенную функцию (в этом случае вызов функции не вставляется).

person sellibitze    schedule 05.06.2010
comment
Volatile не может помочь вам избежать неопределенного поведения здесь — почему? У вас есть источник этого утверждения? - person doublep; 06.06.2010
comment
Стандарт С++, раздел 3.10, параграф 15, - это то место, на которое вам нужно обратить внимание в отношении строгого псевдонима. Там нет упоминания об исключении, связанном с volatile. - person sellibitze; 06.06.2010
comment
Есть случаи, когда это не неопределенное поведение. Например, struct A { int a; }; int main() { X x; *reinterpret_cast<int*>(&x) = 10; } прекрасно и точно определено в соответствии с 9.2/17. Объект имеет тип int, а lvalue также имеет тип volatile int, поэтому псевдонимы работают нормально. - person Johannes Schaub - litb; 06.06.2010
comment
@Johannes: В моем случае T может быть что угодно, только размер соответствует int. Например. подойдет указатель на многих платформах. - person doublep; 06.06.2010
comment
@Johannes: я не имел в виду, что это всегда неопределенное поведение. Я просто хотел сказать, что volatile не будет иметь никакого значения по отношению к 3.10/15. - person sellibitze; 06.06.2010
comment
@sellibitze, ах, теперь это имеет смысл. Почему-то я пропустил. Решает ли этот доступ через изменчивую ссылку проблему псевдонима указателя? часть :) спасибо - person Johannes Schaub - litb; 07.06.2010
comment
Использование memcpy не гарантирует работу, если у адресата нет объявленного типа, а тип, в котором он будет прочитан в следующий раз, не соответствует действующему типу источника. Если кто-то хочет написать доказательство оптимизации кода, необходимо загружать и хранить отдельные символы таким образом, чтобы их нельзя было интерпретировать как операцию над массивом символов. - person supercat; 23.03.2017

Volatile не может помочь вам избежать неопределенного поведения здесь.

Ну, что-либо относительно volatile в стандарте несколько неясно. Я в основном согласился с вашим ответом, но теперь я хотел бы немного не согласиться.

Чтобы понять, что означает volatile, стандарт не ясен для большинства людей, особенно для некоторых авторов компиляторов. Лучше подумать: при использовании volatile (и только тогда) C/C++ представляет собой ассемблер высокого уровня.

При записи в volatile lvalue компилятор выдаст STORE или несколько STORE, если одного недостаточно (volatile не подразумевает атомарность).

При записи в volatile lvalue компилятор выдаст LOAD или несколько LOAD, если одного недостаточно.

Конечно, там, где нет явной ЗАГРУЗКИ или СОХРАНЕНИЯ, компилятор просто выдаст инструкции, подразумевающие ЗАГРУЗКУ или СОХРАНЕНИЕ.

sellibitze предложил лучшее решение: использовать memcpy для переинтерпретации битов.

Но если все обращения к области памяти выполняются с volatile lvalues, совершенно ясно, что строгие правила псевдонимов не применяются. Это ответ на ваш вопрос.

person curiousguy    schedule 15.07.2012
comment
-1: Во-первых, это не форум; мы не рассматриваем другие ответы в ответах. Если вы считаете, что у вас есть лучший ответ, то напишите ответ, который касается вопроса. Во-вторых, что более важно, все, что касается volatile, в стандарте несколько неясно. Нет, это не так. Стандарт очень четко описывает, как работает volatile и non volatile в отношении абстрактной машины. - person Nicol Bolas; 21.07.2012
comment
@NicolBolas Во-вторых, что более важно, все, что касается volatile, несколько неясно в стандарте. Нет, это не так. Многие люди думают, что это крайне неясно. Если вы думаете, что это ясно, пожалуйста, объясните, что это значит, и моя интерпретация верна. - person curiousguy; 21.07.2012
comment
@NicolBolas Во-первых, это не форум; За исключением того, что это форум. Мы обсуждаем вещи. Это определение форума. мы не рассматриваем другие ответы в ответах. Итак, я должен обсудить это в комментарии, тогда кто-то скажет мне, что я обсуждаю слишком много вещей в комментарии... - person curiousguy; 21.07.2012
comment
Итак, я должен обсудить это в комментарии, а потом кто-то скажет мне, что я обсуждаю слишком много вещей в комментариях. Точно. Вот как мы не допускаем обсуждения на этот сайт вопросов и ответов, тем самым сохраняя фокус на вопросе. Обычно мы не хотим, чтобы люди обращались к другому ответу, подобному этому, в ответах; мы хотим, чтобы в центре внимания был ответ на вопрос человека. Что, как вы признаете, сделал sellibitze. - person Nicol Bolas; 22.07.2012
comment
@NicolBolas 1) Это слишком велико для комментария. 2) Пожалуйста. Читать. Мой. Отвечать. - person curiousguy; 22.07.2012
comment
@NicolBolas мы хотим, чтобы в центре внимания был ответ на вопрос человека. Что, как вы признаете, сделал sellibitze на самом деле, он не ответил на вопрос об использовании volatile (только конкретный пример использования volatile). Я ответил на вопрос об использовании volatile. sellibitze сказал: нет, это не работает. Я сказал: работает, но не так, как вы написали. В любом случае, это плохая идея, и следуйте совету sellibitze, чтобы использовать memcpy. Ваши атаки не оправданы. - person curiousguy; 22.07.2012
comment
Поведение volatile доступа определяется реализацией, поэтому реализация может определить поведение таким образом, чтобы не защищаться от UB, связанного с псевдонимами. Компилятор, написанный здравомыслящими зрелыми людьми, не должен иметь проблем с записью и чтением volatile местоположения с использованием разных типов. Увы, некоторые разработчики компиляторов скорее будут искать оправдания для обращения с чем-то как с неопределённым поведением, чем сгенерировать полезный код. - person supercat; 23.08.2015