Forger 22 14 марта, 2023 Опубликовано 14 марта, 2023 · Жалоба 42 minutes ago, Arlleex said: Но, опять же, у Вас шаблонная функция, я бы хотел избежать этого Избавьтесь лучше от uniun, он действительно для этой задачи не совсем уместен ) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 134 15 марта, 2023 Опубликовано 15 марта, 2023 · Жалоба 13 часов назад, Arlleex сказал: Идея ясна, спасибо. Вот, придумался более простой вариант: struct sendable {}; struct a : public sendable { }; struct b {}; inline void send_msg(sendable const & from, size_t size) { auto pSrc = static_cast<void const *>(&from); ............... } template<typename T> void send_msg(T const & data) { send_msg(data, sizeof(T)); } template<typename T, size_t items> void send_msg(T const (& data)[items]) // если вдруг потребуется передавать массив структур { send_msg(data[0], sizeof(T) * items); } void test() { a Good = {}; a Good2[2] = {{}, {}}; b Bad = {}; send_msg(Good); send_msg(Good2); send_msg(Bad); // error: no matching function for call to 'send_msg(const b&, unsigned int)' // <- note: no known conversion for argument 1 from 'const b' to 'const sendable&' } 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 177 15 марта, 2023 Опубликовано 15 марта, 2023 · Жалоба 57 минут назад, Сергей Борщ сказал: Вот, придумался более простой вариант... Вот, такой нравится вариант, он мне полностью понятен по крайней мере)) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 177 15 марта, 2023 Опубликовано 15 марта, 2023 · Жалоба Что-то читал я про union-ы в C++ и пришел к выводу, что в комитете дурь очень забористая. Оказывается, нельзя в плюсах репрезентовать битовое представление, как это делалось обычно union { u32 i; float f; } u; int main() { u.f = 3.1f; printf("%d", u.i); // undefined behavior in C++ return 1; } И выход из ситуации через memcpy(), placement-new [] и иже им подобным костылям с трехэтажным монструозным синтаксисом. Почему Страуструп и Ко просто не взял и не скопировал у Си? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 22 15 марта, 2023 Опубликовано 15 марта, 2023 · Жалоба 1 hour ago, Arlleex said: Оказывается, нельзя в плюсах репрезентовать битовое представление, как это делалось обычно Какой компилятор? Покажите текст ошибки при компиляции. У меня компилятор не ругается - ARM v6.19 в режиме C++17 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 177 15 марта, 2023 Опубликовано 15 марта, 2023 · Жалоба А здесь совершенно не причем, ругается или не ругается компилятор. Он не будет ругаться, а по стандарту вышеуказанный хук слева с union-ом оборачивается UB. О как. Компилятор у меня ARM CLang (keil-овский v6). Он, конечно, код пока что генерит правильно, однако я уже достаточно вкурил, чтобы понять, что плюсоводы такое использование union не одобряют. Одобряют только (и только лишь) хранение разных типов внутри одного кусочка памяти. Обращаться на чтение можно только к элементу, тип которого совпадает с типом элемента на последнюю запись значения в union. Это так называемая установка активного члена union-а. Совсем одурели, в америке своей. union { int i; float f; unsigned int ui; } u; int main() { u.i = 10; // set 'i' member at 'active' unsigned int ui = u.i; // ok (last active type - int) u.f = 3.0f; float f = u.f; // ok int i = u.ui; // undefined behavior } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 22 15 марта, 2023 Опубликовано 15 марта, 2023 · Жалоба 14 minutes ago, Arlleex said: Он не будет ругаться, а по стандарту вышеуказанный хук слева с union-ом оборачивается UB. О как. Ну это логично, данные для float и для int храняться в памяти по-разному, union позволяет обманывать компилятор, нарушая его логику. Поведение действительно непредсказуемо. Тут напрашивается явное преобразование: u.f = 3.1f; auto i = static_cast<uint32_t>(u.f); printf("%d", i); Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 177 15 марта, 2023 Опубликовано 15 марта, 2023 · Жалоба 19 минут назад, Forger сказал: Тут напрашивается явное преобразование... Никакие касты (ни static, ни reinterpret) не влияют на UB при доступе к члену union другого типа. Это я тоже почитал(( Однако в Вашем примере static_cast выполняет немного другую роль, и, на мой взгляд, каст лишний, ибо по-умолчанию float->int произойдет автоматом с изменением представления и отбрасыванием дробной части. В этой связи у меня более общий вопрос, но имеющий непосредственное отношение к текущей задаче: желая сэкономить память, я совместил"рабочий" байтовый буфер со структурами, по которым мне удобно обращаться к протокольным заголовкам и данным static union uRxMsg { struct { u32 cmd, arg, crc; } sysInf; u8 buf[MAX_RX_MSG_SIZE]; } RxMsg; В RxMsg.buf по байтикам пишет драйвер-разгербатор входящего потока по интерфейсу, а обработчик сообщений декодирует сообщения, обращаясь к ним по RxMsg.sysInf (и другим, если добавляются). Получается, по правилам C++ я так сделать не могу. И как тогда могу? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 22 15 марта, 2023 Опубликовано 15 марта, 2023 · Жалоба 9 minutes ago, Arlleex said: ибо по-умолчанию float->int произойдет автоматом с изменением представления и отбрасыванием дробной части. Да, можно без cast. Просто cast полезен для указания прогеру на потенциально скверные места но все равно нужно делать явное преобразование. В таком случае компилятор сам вызовет внутреннюю функцию для преобрвазования float в u32 и разместит результат во явной временной переменной, в данном случае в стеке. В конце концов, если напрягает доп строчка кода , то сделайте так: printf("%d", static_cast<uint32_t>(u.f)): 10 minutes ago, Arlleex said: Никакие касты (ни static, ни reinterpret) не влияют на UB при доступе к члену union другого типа Не влияют, но указывают начинающего с++ прогеру, что тут что-то нечисто )) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xvr 12 15 марта, 2023 Опубликовано 15 марта, 2023 · Жалоба 3 hours ago, Arlleex said: Что-то читал я про union-ы в C++ и пришел к выводу, что в комитете дурь очень забористая. Стандарт не описывает битовое представление int и float. Так что совершенно логично, если вы записали int, а читаете float, то стандарт не может дать никаких гарантий что именно вы прочитаете. Так что UB вполне логично. То же самое и в С, но там на это смотрят сквозь пальцы - что хотите, то и читайте 🙂 Просто в С++ сразу расписались, что при таком обращении с памятью они ничего не гарантируют. А гарантируют только то, что если вы писали как int, то и считать можете как int. В С++ есть UB, которые могут показаться гораздо более странными. Например переполнение при инкременте знакового целого - UB. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 22 15 марта, 2023 Опубликовано 15 марта, 2023 · Жалоба 2 hours ago, Arlleex said: Получается, по правилам C++ я так сделать не могу. Можно, почему же нет )) У вас там только беззнаковые целые числа. UB возможно лишь в вашем коде, не в коде встроенных библиотек. А это отслеживается и отлаживается. Безусловно нужно заботится о правильном заполнении данными buf[MAX_RX_MSG_SIZE] , чтобы при разборе через sysInf не вылезли неприятности. Но компилятор не может об этом знать, поэтому никак это не запрещает. К слову, я сам подобным образом делал и продолжаю делать. Но такие "фишки" лучше тщательно отлаживать/тестировать и прятать глубоко в коде, чтобы "наружу" не вылезло. Это не только к плюсам относится, это вообще ) зы Вообще, C++ заметно более строгий чем С. Эта потребность возникла не на ровном месте по прихоти группки людей. Это как ПДД - каждый пункт которых написан кровью. Тут что-то подобное, но не такое кровожадное )) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 177 16 марта, 2023 Опубликовано 16 марта, 2023 · Жалоба 8 часов назад, xvr сказал: В С++ есть UB, которые могут показаться гораздо более странными. Например переполнение при инкременте знакового целого - UB. Как раз переполнение знаковых с соответствующим UB - это не присущая C++ особенность. В Си тоже переполение знакового - UB. И этот UB весьма обоснован. Цитата Просто в С++ сразу расписались, что при таком обращении с памятью они ничего не гарантируют. Понимаете ли, в чем основная соль. Соль в том, что при оптимизациях с потенциальным UB могут выкидываться целые куски кода, как будто их и не было, либо компилятор может генерить полную дичь. Я бы понял, если в случаях с union-ами сделали поведение, определяемое реализацией. Я бы проверил на своем компиляторе и забыл. А сейчас получается, что я тупо не могу написать оптимизированный по объему RAM и скорости выполнения код! Видете ли, гуру со стековерфлоу, ссылаясь на параграфы из стандарта C++, приходят к примерно одному мнению - чтобы наложить структуру на буфер (я про подход, где гарантированно не будет проблем с активизацией членов union и strict aliasing), надо *боже дай мне сил не материться* скопировать этот буфер в объект такой структуры. А если я плюю на все это и пишу в union буфер и структуру (как показывал выше в коде), то это потенциальный UB и при сборках/пересборках результат может быть совершенно разным - как карта ляжет. А глядя вкупе на тот ворох метафигни, которую сейчас в современные плюсы добавили у меня возникает закономерный вопрос: получается, C++ больше развивают в сторону каких-то питонов с рубами, чем в сторону языков, на которых по-прежнему можно писать эффективный код для любой архитектуры. Я как ни сяду писать что-то на плюсах (потому что есть у него кое-что такое, чего нет в Си), вечно упираюсь лбом в какую-то наитупейшую мелочь, которая, как мне казалось, давным давно должна была быть разрулена. Это, скорее, риторические вопросы, у меня немного бомбит со всего этого, прошу отнестись с пониманием. Если же есть альтернативное мнение - давайте обсудим. 7 часов назад, Forger сказал: У вас там только беззнаковые целые числа. UB возможно лишь в вашем коде, не в коде встроенных библиотек. А это отслеживается и отлаживается. Это для примера я беззнаковые привел. А по факту в структурах лежит черти что и что там будет лежать через пару итераций доработок ПО мне не ведомо. Я лишь атрибутами выравнивания/размещения гарантирую корректность расположения структур, наличие padding-а и т.д. для безопасной работы с выровненными данными на Cortex-M0, не умеющим невыровненный доступ. Цитата Эта потребность возникла не на ровном месте по прихоти группки людей. Это как ПДД - каждый пункт которых написан кровью. Тут что-то подобное, но не такое кровожадное )) Открывая стандарт, я не вижу ту самую кровь, там не пишут, почему та или иная штука приводит к UB. Там просто констатируется факт - а уж сообщество дальше додумывает, почему так. И это печально. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 22 16 марта, 2023 Опубликовано 16 марта, 2023 · Жалоба 51 minutes ago, Arlleex said: Открывая стандарт, я не вижу ту самую кровь, там не пишут, почему та или иная штука приводит к UB. В ПДД тоже нет ничего про кровь )) 59 minutes ago, Arlleex said: А глядя вкупе на тот ворох метафигни, Никаких таких проблем с переходом с С на плюсы у меня лично не было. Как применял union и другие чисто сишные штуки для подобных целей так и применяю. Просто стал меньше использовать сомнительных и неявных конструкций, что положительно сказалось на надежности и качестве кода (хотя, может, просто опыта прибавилось не наступать на грабли). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 134 16 марта, 2023 Опубликовано 16 марта, 2023 · Жалоба 2 часа назад, Arlleex сказал: приходят к примерно одному мнению - чтобы наложить структуру на буфер (я про подход, где гарантированно не будет проблем с активизацией членов union и strict aliasing), надо *боже дай мне сил не материться* скопировать этот буфер в объект такой структуры Есть еще вариант с placement new(). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 177 16 марта, 2023 Опубликовано 16 марта, 2023 · Жалоба А placement new отменяет все компиляторные хотелки относительно strict aliasing? Т.е. не будет ли это по-прежнему UB? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться