A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined.
Допустим есть
int *p_int; void *p_void;
.
Как узнать допустимые значения для p_void в
p_int = p_void;
?
допустим мы говорим о clang/gcc/icc + linux + amd64.
Для gcc мне ответили (разработчики gcc), что в случае с gcc/linux/amd64,
они хотят 4 байта выравнивание, но не пояснили где в документации
gcc об этом можно прочитать. В ABI, который они реализуют для amd64,
сказано, что misaligned доступ не должен вызывать проблем, поэтому
они как бы усили требования по срванению с ABI.
Также интересно, что думает об этом C11,C++11, C++14?
Здравствуйте, Zhendos, Вы писали:
Z>Вопрос навеян: Z>
Z>6.3.2.3/7:
Z>A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined.
Z>Допустим есть
int *p_int; void *p_void;
. Z>Как узнать допустимые значения для p_void в
p_int = p_void;
?
Z>допустим мы говорим о clang/gcc/icc + linux + amd64.
Z>Для gcc мне ответили (разработчики gcc), что в случае с gcc/linux/amd64, Z>они хотят 4 байта выравнивание, но не пояснили где в документации Z>gcc об этом можно прочитать. В ABI, который они реализуют для amd64, Z>сказано, что misaligned доступ не должен вызывать проблем, поэтому Z>они как бы усили требования по срванению с ABI.
Z>Также интересно, что думает об этом C11,C++11, C++14?
Не совсем понято, в чём собственно проблема? Нужно узнать alignment для хранения int? В gcc есть оператор __alignof__. Пишешь
printf("%zu\n", __alignof__ (int));
и узнаёшь значение для твоей платформы. Само собой, на разных платформах это значение может быть разным, поэтому если это и прописано, то скорее в документации на платформу, чем в С-стандартах.
_>Не совсем понято, в чём собственно проблема? Нужно узнать alignment для хранения int? В gcc есть оператор __alignof__. Пишешь
printf("%zu\n", __alignof__ (int));
и узнаёшь значение для твоей платформы. Само собой, на разных платформах это значение может быть разным, поэтому если это и прописано, то скорее в документации на платформу, чем в С-стандартах.
Проблема что на x86 32 бита он выдает 4, хотя я видел
полно говнокода, который на x86 приводит "char *", выравненный
хрен знает как, к "int *" и начинает работать.
Получается весь этот код невалидный даже для той
платформы, для которой он писался (платформа = ОС+компилятор(gcc)+CPU(x86))?
Здравствуйте, sokel, Вы писали:
S>Здравствуйте, Zhendos, Вы писали:
Z>>misaligned доступ не должен вызывать проблем, поэтому Z>>они как бы усили требования по срванению с ABI.
S>Где-то не вызывает проблем, где-то вызывает, поэтому в общем случае the behavior is undefined.
Так я привел конкретную платформу, мне для нее и нужно понять,
"вообще" мне не интересно.
Здравствуйте, Zhendos, Вы писали:
Z>Также интересно, что думает об этом C11,C++11, C++14?
В C++ дела обстоят иначе.
можно кастовать Т1* в Т2* если alignof(T1) >= alignof(T2)
иначе *значение результата каста не определено*, т.е. в самом касте неопределенного поведения нету, UB появляется только если разыменовать результат каста
Здравствуйте, Abyx, Вы писали:
A>Здравствуйте, Zhendos, Вы писали:
Z>>Также интересно, что думает об этом C11,C++11, C++14?
A>В C++ дела обстоят иначе. A>можно кастовать Т1* в Т2* если alignof(T1) >= alignof(T2) A>иначе *значение результата каста не определено*, т.е. в самом касте неопределенного поведения нету, UB появляется только если разыменовать результат каста
Собственно, это то же самое. И в С выравнивание для величины должно быть больше или равным требуемому для этой величины. Это автоматически вытекает из математики для выравнивания.
Здравствуйте, Zhendos, Вы писали:
Z>Здравствуйте, v_andal, Вы писали:
Z>>>Допустим есть
int *p_int; void *p_void;
. Z>>>Как узнать допустимые значения для p_void в
p_int = p_void;
?
_>>Не совсем понято, в чём собственно проблема? Нужно узнать alignment для хранения int? В gcc есть оператор __alignof__. Пишешь
printf("%zu\n", __alignof__ (int));
и узнаёшь значение для твоей платформы. Само собой, на разных платформах это значение может быть разным, поэтому если это и прописано, то скорее в документации на платформу, чем в С-стандартах.
Z>Проблема что на x86 32 бита он выдает 4, хотя я видел Z>полно говнокода, который на x86 приводит "char *", выравненный Z>хрен знает как, к "int *" и начинает работать.
Собственно под словом "платформа" я имел ввиду железо на котором выполняется программа. Извиняюсь, если неверно использовал термин. Однажды мне пришлось писать программу для процессора Alpha. Будучи ещё нубом, я не мудрствуя лукаво указывал int * в середину байтового буфера. На Intel всё это работало. А на Alpha в общем-то тоже работало, но заваливало системные логи сообщениями, что произошло обращение к не выравненной области памяти. Так я и узнал, что лучше лишний раз
memcpy(&int_val, char_ptr, sizeof(int_val));
сделать, либо аккуратно строковый буфер организовывать.
В общем, эти требования по выравниванию возникают из-за требований железа. Чтобы не приходилось в программе выяснять, на каком железе идёт работа, предлагается сразу выравнивать память. Не хочешь выравнивать — попадаешь в серую зону undefined behavior, где-то работать будет, а где-то нет.