У меня есть структура, предназначенная для хранения пользовательских данных (т.е. из плагина). У него есть такой char[]
с заданным максимальным размером для хранения этих данных.
struct A
{
// other members omitted
// data meant to be type punned, only contains PODs
char data[256];
};
Затем есть образец пользовательской структуры со статической функцией для преобразования себя из A
.
struct B
{
int i;
double d;
static B& FromA_ref(A& a)
{
// static_assert that sizeof(B) < sizeof(A::data)
return * reinterpret_cast<B*>(a.data);
}
};
Я компилирую с помощью g++ -O3 -std=c++0x -Wall -o test test.cpp
(GCC 4.6.1).
Это вызывает предупреждение dereferencing type-punned pointer will break strict-aliasing rules
. Я подумал, что все будет в порядке, так как я использовал char[]
в качестве хранилища, которое, как я думал, будет следовать тем же правилам, что и char*
. Я нахожу странным, что это не так. Не так ли? Ну... я не могу изменить это прямо сейчас, так что давайте двигаться дальше.
Теперь рассмотрим следующий метод:
struct B
{
....
static B* FromA_ptr(A& a)
{
// static_assert that sizeof(B) < sizeof(A::data)
return reinterpret_cast<B*>(a.data);
}
}
Поскольку здесь я ничего не разыменовываю, GCC не выводит никаких предупреждений. Этого не происходит, когда я использую свой указатель на B
позже.
A a;
auto b = B::FromA_ptr(a);
b->i = 2; // no warnings.
Но безопасно ли это? Мне кажется, что я пытался обойти проблему, а не решить ее. Для меня ->
все еще каким-то образом разыменовывает переменную.
В качестве альтернативы, есть ли лучший способ добиться эффекта? т.е. получить модифицируемую ссылку (или указатель), приведенную из хранилища внутри другой структуры? (Union не будет работать, поскольку набор сохраняемых типов неизвестен, когда определено A
, и некоторые из них могут быть добавлены через плагины, memcpy
заставит меня копировать данные туда и обратно, хотя это кажется единственным безопасным способом, поэтому далеко)
__may_alias__
? blog.worldofcoding.com/2010/02/ - person Russell Borogove   schedule 03.04.2012__attribute__((aligned(8)));
будет достаточно, так как я не пытаюсь ничего автоматически векторизовать. Вероятно,may_alias
уже говорит GCC обратить внимание на выравнивание, прежде чем делать слишком много странных вещей. - person J.N.   schedule 12.07.2012union { char dat[theSize]; typeWithWorstAlignment dummy; }
. Это позаботится обо всем, кроме проблем с псевдонимами, для которых Стандарт не предлагает решения. Учитывая отсутствие какого-либо решения проблем с псевдонимами, я нахожу странным, что стандарт C11 включает директивы выравнивания, которые на самом деле бесполезны, кроме в обстоятельствах, связанных с каламбуром типов. - person supercat   schedule 13.02.2017