ВходНаше всё Теги codebook 无线电组件 Поиск Опросы Закон Суббота
23 ноября
1021091 Топик полностью
fk0, легенда (26.07.2020 13:47, просмотров: 671) ответил RxTx на Вчера я прочитал что ты написал и планировал самостоятельно поэкспериментировать. Слова это одно, а когда начинаешь разбираться сам легко может быть другое. Не вышло, нет времени, поэтому все что я здесь пишу основано на исходных данных этой темы. Кстати беглое изучение документации на тему memcpy показывает что существует большое пространство для маневра не только с тривиальными ключами компилятора, прагмами и атрибутами но и что важно, с подключаемыми либами/выбором obj
UB значит, что возможное дальнейшее развитие сценария писателями компиляторов не рассматривается. Такого мол изначально не может быть, программист не допустит. Поэтому если при анализе ситуации возникает UB, то нет смысл думать что если то, или если это -- оно в принципе невозможно в корректной программе. Выражение "&IH.conag" само по себе UB. Поэтому заявить, что мол в компиляторе баг и притягивать дальнейшие преобразования типа и вызов memcpy не нужно: в корректной 

программе такого выражения быть не может. Что, есть возражения, что пункт 6.3.2.3.7 нарушен? Нарушен же. Если бы программист прибавил волшебное слово __packed к декларации conag уже не было бы UB (результатом выражения является тип с alignof(type) == 1) и всё сразу заработало бы, но это совершенно другая история. И если ты сейчас пойдёшь в багтрекер заводить баг тебя ровно в это же и ткнут. Чего спорить -- заведи баг в gcc, clang, keil -- оно везде одинаково (даже может в MSVC).


Он описывает случай, когда существовал типизированный указатель. При обращении к этому указателю средствами языка с учетом типа всё было нормально. Этот указатель "конвертируется" т.е. при неизменном значении у него меняется тип. Смена типа приводит к новой интерпретации данных, что влечет за собой новый метод доступа. (Либо иной вариант кода, либо иную инструкцию итд). При этом новый метод доступа/инструкция CPU может ужесточить требования выравнивания к адресу. Дальнейшая попытка обращения средствами языка к данному типу данных приведет к UB. Вот именно об этом пункт 6.3.2.3.7 и предупреждает.
И ТОЛЬКО об этом. Пункт 6.3.2.3.7 не о том, что взятие указателя невыровненного int'а это сразу же автоматически UB. Ко всему прочему каста при этом нет.
Операция взятия указателя (адреса) на невыровненные данные совершенно валидна в языке C, никакого UB именно при взятии и дальнейшем существовании такого указателя нет.


A разве именно выделенное жирным и не происходит? Только вот про дальнейшую попытку доступа в оригинале ни слова: "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 pointed-to type, the behavior is undefined." Всё, точка.


Приведение каких-то аргументов про x86, про то что было вчера и на прошлой неделе, про то, что в на какой-то платформе работает, значит мол и на всех должно -- это не аргументы.


В рамках стандартного подможества языка, если аппелировать к стандарту, проблемы вообще нет. Она возникает из-за непродуманной реализации нестандартного расширения. Коим я уже многократно предложил просто не пользоваться. Т.к. по факту оно ничего толком не даёт, кроме проблем, его именно потому и не хотят принимать в стандарт.


Значения выравнивания адресов по умолчанию определяются (и имеют значение) для кодогенератора и для конкретного прцессора. Язык о них ничего не знает.


Язык знает. В языке C это знание неявное, можно извлечь через sizеof структуры. В C++11 уже явное, через ключевые слова alignas и alignof. Вот не знай язык этого, не было и проблемы. Оптимизатор не смог подставить бы другую реализацию memcpy, не знай он истиный alignof выражения. А он знает и достаёт, оттого и. И выкидывать эту "багофичу" никто не вздумает, т.к. она заметно ускоряет корректно написанные программы (повторюсь, где хотя бы __packed перед членом структуры записали).


Все что ты писал о оптимизации верно, и трабла восходит к оптимизации и дилемме либо копировать memcpy побайтно, либо попытаться оптимизировать.

Именно так. Но какую "lowlevel" документацию читать и что делать? Проблема возникает не при кодогенерации ассемблера для конкретной платофмы, а ещё на уровне работы с промежуточным (условно, трёхадресным) кодом, который о платформе ещё ничего не знает. Более того, я показывал, что проблему можно воспроизвести на C++ пытаясь руками написать оптимальный код. И без "упакованных структур" всё работает с другими типами, и только они вызывают проблемы. И __packed перед членом структуры тоже должен в этой ситуации исправить проблему.


Странно что ты не знаешь или не узнаешь типы u32,s32,u16,s16,u8,s8 итд, например f32,f64. Это типы Linux Kernel.

Знать может я знаю, но использовать в userspace программах такие типы нет смысла и вообще плохо. Потому, что u32 будет излишне тяжел для 16-битной платформы, например, и наоборот u16 тяжёл для арма (по лишней инструкции на каждую операцию). С 64-битами тоже не лучше, если кто-то напишет u32 вместо intptr_t. И u64 для адреса тоже ничем не лучше -- во-первых тяжёлый тип для 32-битной платформы, во-вторых бесконечный поток багов из-за знаковости (0xffff.... или 0x0000... в старших битах) или попросту не инициализации старпших бит (пример -- lldb из состава llvm, который делали только на 64 бита и там по-моему до сих пор баги при запуске на 32-битном арме...)

[ZX]