Здравствуйте, Klirik, Вы писали:
K>Есть вот такой фрагмент:
... K>Как его победить?
Это предупреждение имеет смысл. Дело в том, что не на всех архитекторах процессора это можно делать. Например может быть условие, что переменная типа int может лежать только по выровненному адресу (ну например адрес должен делиться на 4 без остатка). Т.е если у вас pPtr == 1025, то при выполнении Вашей функции с типом int произойдет аппаратное прерывание и программа вылетит .
Если Вы уверены, что у Вас этого нет (например работаете только на x86 процессорах), то просто запретите это предупреждение .
Re[2]: dereferencing pointer ... does break strict-aliasing
Если обратили внимание на сам пример — там достаточно недвусмысленное название функции .
S>Если Вы уверены, что у Вас этого нет (например работаете только на x86 процессорах), то просто запретите это предупреждение .
Эта версия используется только на тех архитектурах, где выравнивание неважно. На тех, где возможно исключение, используется другой код.
Тем не менее — "просто запретить" — тоже далеко не всегда вариант. Например, если вы делаете пакет для gentoo с усиленной политикой, где при наличии подобного варнинга он просто не будет установлен в систему, либо будет считаться ненадёжным.
Мне хочется найти не обходное, а действительное решение этой проблемы.
Re[3]: dereferencing pointer ... does break strict-aliasing
Здравствуйте, Klirik, Вы писали:
K>Если обратили внимание на сам пример — там достаточно недвусмысленное название функции .
Ну мало ли, может Вы не знаете что такое выравнивание Прошу прощения за ликбез.
S>>Если Вы уверены, что у Вас этого нет (например работаете только на x86 процессорах), то просто запретите это предупреждение .
K>Эта версия используется только на тех архитектурах, где выравнивание неважно. На тех, где возможно исключение, используется другой код. K>Тем не менее — "просто запретить" — тоже далеко не всегда вариант. Например, если вы делаете пакет для gentoo с усиленной политикой, где при наличии подобного варнинга он просто не будет установлен в систему, либо будет считаться ненадёжным.
По моему проблем нет: K>Эта версия используется только на тех архитектурах, где выравнивание неважно. На тех, где возможно исключение, используется другой код.
используйте везде этот "другой код".
Если этот код используется только на "архитектурах, где выравнивание неважно", то значит стоят всякие #ifdef. Ну и добавьте туда еще
#pragma warning( push)
#pragma warning( disable : ???)
// код функции#pragma warning( pop )
Пример для VC++, gcc давно не использовал.
K>Мне хочется найти не обходное, а действительное решение этой проблемы.
Вы бы объяснили что именно хотите. Так как на уровне этой функции это предупреждение компилятора совершенно по делу. Т.е. решение нужно искать на уровень выше. Или все же плюнуть на предупреждение, но добавив защиту (assert, static_assert, #ifdef и т.п.)
Re: dereferencing pointer ... does break strict-aliasing rul
3.10 Lvalues and rvalues
15. If a program attempts to access the stored value of an object through an lvalue of other than one of the following
types the behavior is undefined 48):
the dynamic type of the object,
a cv-qualified version of the dynamic type of the object,
a type that is the signed or unsigned type corresponding to the dynamic type of the object,
a type that is the signed or unsigned type corresponding to a cv-qualified version of the dynamic type of
the object,
an aggregate or union type that includes one of the aforementioned types among its members (including,
recursively, a member of a subaggregate or contained union),
a type that is a (possibly cv-qualified) base class type of the dynamic type of the object,
a char or unsigned char type.
__________________
48) The intent of this list is to specify those circumstances in which an object may or may not be aliased.
А вот что стандарт разрешает:
3.9 Types
For any object (other than a base-class subobject) of POD type T, whether or not the object holds a valid
value of type T, the underlying bytes (1.7) making up the object can be copied into an array of char or
unsigned char.36) If the content of the array of char or unsigned char is copied back into the
object, the object shall subsequently hold its original value. [Example:
#define N sizeof(T)
char buf[N];
T obj; // obj initialized to its original value
memcpy(buf, &obj, N); // between these two calls to memcpy,
// obj might be modified
memcpy(&obj, buf, N); // at this point, each subobject of obj of scalar type
// holds its original value
—end example]
соглашусь, что всё это мутно
под алиасингом я понимаю синонимы для объектов и когда вы спускаетесь до void*, компилятор теряется и не знает, что вы через этот указатель можете изменить\прочитать. это заставляет его отказаться от некоторых типов оптимизаций. надо работать в типизированном мире и как можно реже спускаться до char*, void*, тогда компилятору будет легче
Re[2]: dereferencing pointer ... does break strict-aliasing
это нормально, если побайтное копирование даст тот же результат, что и выполнение оператора присваивания. Это будет верно не для всех типов T.
Что именно имеется ввиду у ТС не понятно.
Хотя если судить по названию функции и стоит только задача убрать заботливое предупреждение от компилятора и использовать только на x86, то может быть и нормально.
Re[2]: dereferencing pointer ... does break strict-aliasing
Здравствуйте, uzhas, Вы писали:
U>15. If a program attempts to access the stored value of an object through an lvalue of other than one of the following U>types the behavior is undefined 48):
U>
U> the dynamic type of the object, U>... U> an aggregate or union type that includes one of the aforementioned types among its members (including, U>recursively, a member of a subaggregate or contained union), U>... U>
Дело немного в другом.
Понятно, что оригинальный вариант ( *(T*)pPtr = tVal; ) с прямым преобразованием типов должен вызывать предупреждение об undefined behavior — как раз покуда void* не является типом объекта.
Мне непонятно, почему такая же проблема возникает с union, который вроде как раз должен победить ситуацию.
Напомню:
template < typename T > void UnalignedWrite ( void * pPtr, const T & tVal )
{
union {
void *pVoid;
T *pT;
} u;
u.pVoid = pPtr;
*u.pT = tVal;
}
Здесь ровно тоже предупреждение почему-то возникает на строчке *u.pT = tVal; Хотя здесь нет вообще ни одного приведения типов.
Такое ощущение, что gcc где-то применил оптимизацию до проверки на выравнивание — а потом уже проверил и решил ругнуться.
И — опять же, я уже упоминал — если убрать инициализацию u.pVoid = pPtr строчкой выше, то это предупреждение исчезает.
Вопрос — каким образом u.pVoid влияет на поведение компилятора по отношению к u.pT?
Ещё раз, иначе:
есть int *pInt, a. Разве присваивание *pInt = a может вызывать ошибку алиасинга? Всё же типизировано!
А если так — то какое дело, компилятору что int *pInt является членом какого-то union?
Под приведённую выше цитату из Стандарта не попадает только то, что членом union является не сам тип, а указатель на него.
Re[3]: dereferencing pointer ... does break strict-aliasing
Здравствуйте, Klirik, Вы писали:
... K>Дело немного в другом. K>Понятно, что оригинальный вариант ( *(T*)pPtr = tVal; ) с прямым преобразованием типов должен вызывать предупреждение об undefined behavior — как раз покуда void* не является типом объекта. K>Мне непонятно, почему такая же проблема возникает с union, который вроде как раз должен победить ситуацию.
... K>Здесь ровно тоже предупреждение почему-то возникает на строчке *u.pT = tVal; Хотя здесь нет вообще ни одного приведения типов.
здесь есть попытка передачи информации _между_ типами. Это и конфликтует со strict aliasing. Единственное послабление — работа через unsigned char* причем мееедленно а ля memcpy руками.
K>Такое ощущение, что gcc где-то применил оптимизацию до проверки на выравнивание — а потом уже проверил и решил ругнуться.
ему практически положить на выравнивания. Подумаешь программа всхлипнет "bus error" и склеит ласты — выравнивания гцц особо не волнуют.
... K>А если так — то какое дело, компилятору что int *pInt является членом какого-то union?
потому что оптимизатор имеет право считать запись T* и чтение int* (и наоборот) не пересекающимися и выбросить вообще если то что было записано как int* не читается как int*.
есть классическая дока по strict aliasing от Mike Acton пожалуйста почитайте — а то стандарты пишут буквоеды для буквоедов там трудно это воспринимать.
Re[4]: dereferencing pointer ... does break strict-aliasing
Здравствуйте, SleepyDrago, Вы писали:
SD>есть классическая дока по strict aliasing от Mike Acton пожалуйста почитайте — а то стандарты пишут буквоеды для буквоедов там трудно это воспринимать.
Вот за это спасибо
В разделе "Casting through a union (2)" как раз нашёл подобный случай с упоминанием warning-а gcc как false positive. Похоже, это оно и есть. Придётся, видимо, в это конкретное место лепить какую-нибудь прагму
Re[4]: dereferencing pointer ... does break strict-aliasing
K>>Такое ощущение, что gcc где-то применил оптимизацию до проверки на выравнивание — а потом уже проверил и решил ругнуться.
D>а почему просто не добавить -fno-strict-aliasing к опциям gcc?
Проект немаленький, к тому же собирается под разные платформы (и под те, где unaligned-копирование объектов возможно только как блобов (т.е. через memcpy)). В целом такие ситуации компилятор хорошо замечает, и не хотелось бы просто избавляться от "надоедливых" напоминаний, но разобраться, почему они возникают.
К тому же — (я уже упоминал) — в некоторых случаях (усиленный gentoo) сборка такого проекта всё равно выкусит из опций -fno-strict-aliasing, а потом громко ругнётся в конце на "poor programming practice" и посчитает весь пакет в целом ненадёжным, а то и вообще откажется устанавливать его из-за этого в систему.
Re[5]: dereferencing pointer ... does break strict-aliasing
Здравствуйте, Klirik, Вы писали:
K>В разделе "Casting through a union (2)" как раз нашёл подобный случай с упоминанием warning-а gcc как false positive. Похоже, это оно и есть.
ваш случай я бы отнес к "Casting through a union (3)"
Occasionally a programmer may encounter the following INVALID method for creating an alias with a pointer of a different type:
0 typedef union
1 {
2 uint16_t* sp;
3 uint32_t* wp;
4 } U32P;
Re: dereferencing pointer ... does break strict-aliasing rul
Здравствуйте, Klirik, Вы писали:
K>Мне хочется найти не обходное, а действительное решение этой проблемы.
если Вам нужно на самом деле взять 4-х байтовый int из произвольного места "правильным способом", то читайте его байтами.
Re: dereferencing pointer ... does break strict-aliasing rul