Msgstr "разглаживающий тип-караульный указатель нарушит правила строгого сглаживания"
Я использую код, в котором я передавал enum * в int *. Что-то вроде этого:
enum foo { ... }
...
foo foobar;
int *pi = reinterpret_cast<int*>(&foobar);
При компиляции кода (g++ 4.1.2) появляется следующее предупреждающее сообщение:
dereferencing type-punned pointer will break strict-aliasing rules
Я отправил это сообщение в Google и обнаружил, что это происходит только при включенной строгой оптимизации псевдонимов. У меня есть следующие вопросы:
- Если я оставлю код с этим предупреждением, будет ли он генерировать потенциально неправильный код?
- Есть ли способ обойти эту проблему?
- Если этого не происходит, возможно ли отключить строгий псевдоним из исходного файла (потому что я не хочу отключать его для всех исходных файлов, и я не хочу делать отдельное правило Makefile для этот исходный файл)?
И да, мне действительно нужно подобное наложение.
Ответы
Ответ 1
В порядке:
-
Да. GCC будет считать, что указатели не могут иметь псевдоним. Например, если вы назначаете через один, а затем читаете от другого, GCC может в качестве оптимизации переупорядочить чтение и запись - я видел, что это происходит в производственном коде, и отлаживать его не нравится.
-
Несколько. Вы можете использовать объединение, чтобы представлять память, которую вам нужно переосмыслить. Вы можете использовать reinterpret_cast
. Вы можете использовать char *
в точке, где вы переосмысливаете память - char *
определяются как способные псевдонимы. Вы можете использовать тип __attribute__((__may_alias__))
. Вы можете отключить допущения псевдонимов глобально, используя -fno-strict-aliasing.
-
__attribute__((__may_alias__))
по используемым типам, вероятно, ближе всего к отключению предположения для определенного раздела кода.
В вашем конкретном примере обратите внимание, что размер перечисления не определен; GCC обычно использует наименьший целочисленный размер, который может быть использован для его представления, поэтому переинтерпретация указателя на перечисление как целое число может оставить вас с неинициализированными байтами данных в полученном целое. Не делай этого. Почему бы просто не привести к достаточно большому целочисленному типу?
Ответ 2
Но зачем ты это делаешь? Он сломается, если sizeof (foo)!= Sizeof (int). Просто потому, что перечисление похоже на целое число, это не значит, что оно хранится как единое целое.
Итак, да, он может генерировать "потенциально" неправильный код.
Ответ 3
Вы можете использовать следующий код для передачи своих данных:
template<typename T, typename F>
struct alias_cast_t
{
union
{
F raw;
T data;
};
};
template<typename T, typename F>
T alias_cast(F raw_data)
{
alias_cast_t<T, F> ac;
ac.raw = raw_data;
return ac.data;
}
Пример использования:
unsigned int data = alias_cast<unsigned int>(raw_ptr);
Ответ 4
Вы просмотрели этот ответ?
Строгое правило псевдонимов делает это установка незаконных, двух несвязанных типов не может указывать на одну и ту же память. Только char * имеет эту привилегию. К сожалению, вы все еще можете возможно, получите некоторые предупреждения, но он компилируется отлично.
Ответ 5
Строгое сглаживание - это параметр компилятора, поэтому вам нужно отключить его из make файла.
И да, он может генерировать неверный код. Компилятор будет эффективно предполагать, что foobar
и pi
не связаны друг с другом и будут считать, что *pi
не изменится, если foobar
изменено.
Как уже упоминалось, используйте static_cast
вместо (и без указателей).