-
- Если компилятор рассматривает void* как int*, то это его
обязанность убедиться в допустимости такой замены в каждом
конкретном вызове. - LightElf(26.07.2020 15:39)
- Так для типа int -- всё корректно. Некорректно для того типа, что
лежит в упакованной структуре. Это не int, потому, что int не может
лежать на невыравненном адресе. Это другой тип. Но в структуре
записано что int, что и приводит к краху. - fk0(26.07.2020 15:43)
- Компилятор знает, что в общем случае void* нельзя приводить к int*.
Компилятор либо знает, что тип лежит в упакованной структуре и
должен генерировать правильный код. Либо компилятор не знает, где
лежит данный конкретный int и тогда должен исходить из худшего (раз
уж он поддерживает такие конструкции). А вот это "здесь читаем,
здесь не читаем, а здесь - рыбу заворачивали" есть косяк и бага. - LightElf(26.07.2020 16:22)
- Косяк и бага в том, что обычный тип int никак не может лежать в
упакованной структуре. Потому, что int не может лежать по
невыравненному адресу. С чем ты не согласен? - fk0(26.07.2020 16:26)
- Блин. Компилятор поддерживает #pragma pack(). Значит утверждение
"int не может лежать по невыровненному адресу" - для этого
компилятора ложно. Или трусы, или крестик. Или компилятор
поддерживает некую фичу и она работает как положено, или не
поддерживает. А вот это вот: "мы поддерживаем-поддерживаем, но все
никак не держится" - детский сад, штаны на лямках. - LightElf(26.07.2020 23:47)
- Ничего не значит. Int -- это конкретный тип данных, на 32-битном арме с атрибутами sizeof(int) == 4 и alignof(int) == 4. А ты хочешь тип с атрибутом aligof(type) == 1. Не может один тип данных проявлять квантовую запутанность и иметь одновременно два значения alignof! Значит это не int, это, условно, unaligned_int. А если это другой тип, это порождает массу сложностей сразу, бьющих преимущественно по программисту, хотя наверное так сделать можно. А если запутанность и fk0(735 знак., 27.07.2020 00:01)
- Блин. Компилятор поддерживает #pragma pack(). Значит утверждение
"int не может лежать по невыровненному адресу" - для этого
компилятора ложно. Или трусы, или крестик. Или компилятор
поддерживает некую фичу и она работает как положено, или не
поддерживает. А вот это вот: "мы поддерживаем-поддерживаем, но все
никак не держится" - детский сад, штаны на лямках. - LightElf(26.07.2020 23:47)
- Косяк и бага в том, что обычный тип int никак не может лежать в
упакованной структуре. Потому, что int не может лежать по
невыравненному адресу. С чем ты не согласен? - fk0(26.07.2020 16:26)
- SciFi же дал ссылку на кейловскую документацию: Taking the address of a field in a #pragma packed struct does
not yield a __packed pointer. Так что это не баг, а фичер: в структуре лежит __packed int, а
берёшь адрес, и брюки превращаются... превращаются брюки...
Идиотизм конечно, но bug report слать действительно бесполезно. - йцyкeн(26.07.2020 15:58, ссылка)
- Тут тонкость в том, что проблема будет только лишь при
разыменовании указателя. Для memcpy() тут исключение. memcpy()
принимающая void* всегда должна работать корректно при любом
значении указателя, выравнен он или не выравнен. Однако в-том то и
дело, что в данном случае без "ручного вмешательства" правильно она
не работает. - RxTx(26.07.2020 16:24)
- В ИАРе как раз "ручное вмешательство" нужно, чтобы получить
хардфолт. Функции memcpy() в ИАРе на самом деле нет, компилятор
подставляет __aeabi_memcpy или __aeabi_memcpy4. __aeabi_memcpy4 не
проверяет выравнивание, считается, что компилятор не промахнётся, и
ИАР не промахивается. Какого чёрта Кейл работает по-другому - для
меня загадка. - йцyкeн(26.07.2020 17:01)
- Угу. Понятно. - RxTx(26.07.2020 17:08)
- Натыкался в этих ваших тырнетах на список весьма доставляющих примеров undefined behavior. Там срывали покровы и открывали глаза. Советую погуглить на эту тему, можете после этого изменить мнение по поводу того, что кому чего должен и почему. - SciFi(26.07.2020 16:27)
- Проблема же уже есть и не при разыменовании указателя, а ещё на этапе компиляции, когда подставилась не та версия memcpy. Расчитанная на честный
int. - fk0(26.07.2020 16:27)
- Вот именно это ты и путаешь. Тебе стоит понять, что "еще на этапе
компиляции" в C++ это одно. Потому что "еще на этапе компиляции"
для инстанциации шаблонов это работает компилятор (и к нему
применим стандарт). А в данном случае то что ты ложно считаешь "еще
на этапе компиляции" было не при работе компилятора. СИ компилер
уже отработал. Это случилось в backend. На фазе
кодогенерации/подстановки оптимизированных инстансов memcpy. - RxTx(26.07.2020 16:55)
- Какая разница. Проблема налицо -- не соответствие типов. Уже
написали 10 раз как её вылечить, через __packed применимое к члену
структуры. Но в целом это тоже костыль, ибо нарваться можно ещё
неизвестно где. Я бы просто не использовал упакованные структуры от
греха подальше. Кроме может быть, очень тривиальных случаев и где
это даёт существенный профит в скорости, объёме памяти и т.п. - fk0(26.07.2020 17:20)
- Я тебя услышал и понял. Спасибо за приятную беседу. - RxTx(26.07.2020 17:45)
- Какая разница. Проблема налицо -- не соответствие типов. Уже
написали 10 раз как её вылечить, через __packed применимое к члену
структуры. Но в целом это тоже костыль, ибо нарваться можно ещё
неизвестно где. Я бы просто не использовал упакованные структуры от
греха подальше. Кроме может быть, очень тривиальных случаев и где
это даёт существенный профит в скорости, объёме памяти и т.п. - fk0(26.07.2020 17:20)
- Вот именно это ты и путаешь. Тебе стоит понять, что "еще на этапе
компиляции" в C++ это одно. Потому что "еще на этапе компиляции"
для инстанциации шаблонов это работает компилятор (и к нему
применим стандарт). А в данном случае то что ты ложно считаешь "еще
на этапе компиляции" было не при работе компилятора. СИ компилер
уже отработал. Это случилось в backend. На фазе
кодогенерации/подстановки оптимизированных инстансов memcpy. - RxTx(26.07.2020 16:55)
- В ИАРе как раз "ручное вмешательство" нужно, чтобы получить
хардфолт. Функции memcpy() в ИАРе на самом деле нет, компилятор
подставляет __aeabi_memcpy или __aeabi_memcpy4. __aeabi_memcpy4 не
проверяет выравнивание, считается, что компилятор не промахнётся, и
ИАР не промахивается. Какого чёрта Кейл работает по-другому - для
меня загадка. - йцyкeн(26.07.2020 17:01)
- Тут тонкость в том, что проблема будет только лишь при
разыменовании указателя. Для memcpy() тут исключение. memcpy()
принимающая void* всегда должна работать корректно при любом
значении указателя, выравнен он или не выравнен. Однако в-том то и
дело, что в данном случае без "ручного вмешательства" правильно она
не работает. - RxTx(26.07.2020 16:24)
- Компилятор знает, что в общем случае void* нельзя приводить к int*.
Компилятор либо знает, что тип лежит в упакованной структуре и
должен генерировать правильный код. Либо компилятор не знает, где
лежит данный конкретный int и тогда должен исходить из худшего (раз
уж он поддерживает такие конструкции). А вот это "здесь читаем,
здесь не читаем, а здесь - рыбу заворачивали" есть косяк и бага. - LightElf(26.07.2020 16:22)
- Так для типа int -- всё корректно. Некорректно для того типа, что
лежит в упакованной структуре. Это не int, потому, что int не может
лежать на невыравненном адресе. Это другой тип. Но в структуре
записано что int, что и приводит к краху. - fk0(26.07.2020 15:43)
- Если компилятор рассматривает void* как int*, то это его
обязанность убедиться в допустимости такой замены в каждом
конкретном вызове. - LightElf(26.07.2020 15:39)