repstosw 18 22 августа, 2021 Опубликовано 22 августа, 2021 (изменено) · Жалоба 50 minutes ago, Сергей Борщ said: Явные приведения типов никто не отменял. operator T() вполне позволяет неявно приводить к целому, над которым все эти операции определены ("я так думаю!"). И ругань идет не на мой класс, а на ваши макросы. Что они делают - мне, на первый взгляд, не совсем понятно, но вот этот ужасный WORDn(x,n) я бы записал так: Макросы тоже не мои. Это выхлоп декомпилятора Hex-rays от IDA Pro. Декомпилятор порождает псевдо-код : он очень похож на Си, но чтоб его запустить, нужно многое пофиксить. Оригинальные макросы были такие - они нарушали правило строгого алиасинга и не учитывали доступ к невыровненным данным: #define BYTEn(x, n) (*((u8*)&(x)+n)) #define WORDn(x, n) (*((u16*)&(x)+n)) #define DWORDn(x, n) (*((u32*)&(x)+n)) После как объявил тип с перегрузками, исправил на такие: #define BYTEn(x, n) (*(UA<u8 >*)( (u8* )&(x)+(n) )) #define WORDn(x, n) (*(UA<u16>*)( (u16*)&(x)+(n) )) #define DWORDn(x,n) (*(UA<u32>*)( (u32*)&(x)+(n) )) Стало уже веселее. Можно даже делать операции, наподобие: BYTEn(x,1)++; --BYTEn(x,1); BYTEn(x,1)+= BYTEn(y,0); BYTEn(x,1)>>=4; BYTEn(y,1)=0; Ну и в финале - обращения к невыровненным данным и операции с ними: *(UA<int>*)p++; --*(UA<int>*)p; *(UA<int>*)p = *(UA<int>*)q ++; *(UA<int>*)p = 15; *((UA<int>*)(UA<uintptr_t>)p+1)=2; 50 minutes ago, Сергей Борщ said: А в целом не игрался бы с приведением в макросах, а сразу исходные vXXX объявлял бы как unaligned<нужный тип> Иногда приходится работать с чужим кодом или с машинными выхлопами. Вручную править такое - руки отсохнут. Вот и приходится искать системные подходы. Претензий к вашему варианту не имею. Изначально, я полагал, что в GCC и в TI CC есть специальные директивы, допускающие объявления указателей на невыровненные данные. наподобие как в IAR и Keil. Оказалось, нет. Пришлось самостоятельно делать. Изменено 22 августа, 2021 пользователем repstosw Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 141 22 августа, 2021 Опубликовано 22 августа, 2021 · Жалоба 5 часов назад, repstosw сказал: Оригинальные макросы были такие - они нарушали правило строгого алиасинга и не учитывали доступ к невыровненным данным: #define BYTEn(x, n) (*((u8*)&(x)+n)) #define WORDn(x, n) (*((u16*)&(x)+n)) #define DWORDn(x, n) (*((u32*)&(x)+n)) После как объявил тип с перегрузками, исправил на такие: #define BYTEn(x, n) (*(UA<u8 >*)( (u8* )&(x)+(n) )) #define WORDn(x, n) (*(UA<u16>*)( (u16*)&(x)+(n) )) #define DWORDn(x,n) (*(UA<u32>*)( (u32*)&(x)+(n) )) Но зачем вы оставили приведение к выровненным типам (u8*)? Достаточно было его заменить на (UA<u8>*) и компилятор бы скушал это молча. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
repstosw 18 23 августа, 2021 Опубликовано 23 августа, 2021 · Жалоба 5 hours ago, Сергей Борщ said: Но зачем вы оставили приведение к выровненным типам (u8*)? Достаточно было его заменить на (UA<u8>*) и компилятор бы скушал это молча. Чтобы были правильно посчитаны смещения +(n). Есть альтернативный вариант, но с ним код получается больше размером: #define BYTEn(x, n) (*(UA<u8 >*)(((uintptr_t)&(x))+ (n) )) #define WORDn(x, n) (*(UA<u16>*)(((uintptr_t)&(x))+((n)*2))) #define DWORDn(x,n) (*(UA<u32>*)(((uintptr_t)&(x))+((n)*4))) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 141 23 августа, 2021 Опубликовано 23 августа, 2021 · Жалоба 15 часов назад, repstosw сказал: Чтобы были правильно посчитаны смещения +(n). Но они же и так будут правильно рассчитаны. Они считаются исходя из размера данных, на которые указывает указатель. Что u16 *, что UA<u16>* указывают на 2 байта, и #define WORDn(x, n) ((*(UA<u16>*)&(x))+(n)) будет точно так же смещаться по 2 байта, но поскольку UA<u16>* указывает на невыровненные данные, компилятор не будет ругаться на приведение типа. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
repstosw 18 24 августа, 2021 Опубликовано 24 августа, 2021 (изменено) · Жалоба 13 hours ago, Сергей Борщ said: #define WORDn(x, n) ((*(UA<u16>*)&(x))+(n)) будет точно так же смещаться по 2 байта, но поскольку UA<u16>* указывает на невыровненные данные, компилятор не будет ругаться на приведение типа. Так не работает, потому что (n) должен входить в состав адреса, не не как добавка к разыменованному значению. Возможно, вы имели в виду вот так: #define BYTEn(x, n) *((UA<u8 >*)&(x)+(n)) #define WORDn(x, n) *((UA<u16>*)&(x)+(n)) #define DWORDn(x,n) *((UA<u32>*)&(x)+(n)) Так работает правильно и без предупреждений. P.S. Проверил на ARM - в обоих случаях код одинаковый по размеру с точностью до байта: так: #define BYTEn(x, n) (*(UA<u8 >*)( (u8* )&(x)+(n) )) и так: #define BYTEn(x, n) *((UA<u8 >*)&(x)+(n)) Изменено 24 августа, 2021 пользователем repstosw Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 141 24 августа, 2021 Опубликовано 24 августа, 2021 · Жалоба 1 час назад, repstosw сказал: Возможно, вы имели в виду вот так: Да, конечно. Запутался в скобках. Поэтому и предлагал шаблонную фунуцию вместо всех трех макросов в самом первом ответе. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
VladislavS 39 12 декабря, 2022 Опубликовано 12 декабря, 2022 · Жалоба В CMSIS есть макросы __UNALIGNED_UINT32_WRITE, __UNALIGNED_UINT16_WRITE, __UNALIGNED_UINT32_READ и __UNALIGNED_UINT16_READ. Можно использовать, это будет компиляторонезависимо. Ну и просто подсмотреть как "взрослые дяди" это делают. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться