Это UB ?
От: LaptevVV Россия  
Дата: 01.07.24 04:33
Оценка:
Создаем union
union D{
int a;
char b[4];     // или std::byte b[4]
};
D temp;
temp.a = 1234;
char byte = temp.b[0];

В прежние времена — делалось так.
А сейчас ?
Где-то у меня в мозгах зацепилось, что это UB.

Размещающий new — не предлагать
reinterpret_cast — можно попробовать.

variant ?
Что-то не совсем то, что мне нужно.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Отредактировано 01.07.2024 4:35 LaptevVV . Предыдущая версия .
Re: Это UB ?
От: Doom100500 Израиль  
Дата: 01.07.24 05:43
Оценка: 17 (2) +1
Здравствуйте, LaptevVV, Вы писали:

LVV>Создаем union

LVV>
union D{
LVV>int a;
LVV>char b[4];     // или std::byte b[4]
LVV>};
LVV>D temp;
LVV>temp.a = 1234;
LVV>char byte = temp.b[0];
LVV>

LVV>В прежние времена — делалось так.
LVV>А сейчас ?
LVV>Где-то у меня в мозгах зацепилось, что это UB.

https://en.cppreference.com/w/cpp/language/union

It is undefined behavior to read from the member of the union that wasn't most recently written. Many compilers implement, as a non-standard language extension, the ability to read inactive members of a union.


У нас на MSVC работает похожий код, написанный мной много лет назад по незнанию.

LVV>Размещающий new — не предлагать

LVV>reinterpret_cast — можно попробовать.

LVV>variant ?

LVV>Что-то не совсем то, что мне нужно.

Предлагают std::bit_cast:

https://en.cppreference.com/w/cpp/numeric/bit_cast

https://stackoverflow.com/questions/11373203/accessing-inactive-union-member-and-undefined-behavior
Спасибо за внимание
Re: Это UB ?
От: σ  
Дата: 01.07.24 06:37
Оценка: :)
Бан в гугле — это не шутки…
Re: Это UB ?
От: T4r4sB Россия  
Дата: 01.07.24 07:40
Оценка: 1 (1) -4 :)
Здравствуйте, LaptevVV, Вы писали:

LVV>Создаем union

LVV>
union D{
LVV>int a;
LVV>char b[4];     // или std::byte b[4]
LVV>};
LVV>D temp;
LVV>temp.a = 1234;
LVV>char byte = temp.b[0];
LVV>

LVV>В прежние времена — делалось так.
LVV>А сейчас ?
LVV>Где-то у меня в мозгах зацепилось, что это UB.

Для чара — нет, не уб. И если внутри функции делается все то тоже не УБ
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[2]: Это UB ?
От: LaptevVV Россия  
Дата: 01.07.24 08:59
Оценка: +5 :)
σ>Бан в гугле — это не шутки…
Не хочешь отвечать — проходи молча мимо.
Здесь со знатоками советуются.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[2]: Это UB ?
От: LaptevVV Россия  
Дата: 01.07.24 09:01
Оценка:
D>Предлагают std::bit_cast:
D>https://en.cppreference.com/w/cpp/numeric/bit_cast
О, спасибо! То, что нужно!
А то я в С++17 сижу и как-то на С++20 не посмотрел.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re: Это UB ?
От: Pzz Россия https://github.com/alexpevzner
Дата: 01.07.24 09:04
Оценка: 1 (1) +1 -2
Здравствуйте, LaptevVV, Вы писали:

LVV>Размещающий new — не предлагать

LVV>reinterpret_cast — можно попробовать.

memcpy, как не странно.

Из указателя на int32_t (ну не int же все же, да?) в указатель на char (я бы взял unsigned char или uint8_t, нафига мне парить себе мосг, знаковый мне char сегодня попался или беззнаковый).

Компилятор понимает, что если memcpy делается для таких маленьких порций данных, то не надо превращать его в вызов библиотечной фуккции, которая копирует большие объемы со скоростью курьерского поезда, творческоги примененяя SSE-регистры
Re[2]: Это UB ?
От: flаt  
Дата: 01.07.24 09:08
Оценка: -1 :)
Здравствуйте, Pzz, Вы писали:

Pzz>memcpy, как не странно.


И bit_cast это как раз memcpy.
Re[2]: Это UB ?
От: rg45 СССР  
Дата: 01.07.24 09:15
Оценка: :)
Здравствуйте, σ, Вы писали:

σ>Бан в гугле — это не шутки…


Ты личико сделай попроще, умник.
--
Re[2]: Это UB ?
От: LaptevVV Россия  
Дата: 01.07.24 14:26
Оценка:
Pzz>memcpy, как не странно.
Pzz>Из указателя на int32_t (ну не int же все же, да?) в указатель на char (я бы взял unsigned char или uint8_t, нафига мне парить себе мосг, знаковый мне char сегодня попался или беззнаковый).
Да, это само собой.
Pzz>Компилятор понимает, что если memcpy делается для таких маленьких порций данных, то не надо превращать его в вызов библиотечной функции, которая копирует большие объемы со скоростью курьерского поезда, творчески применяя SSE-регистры
Очень интересно!
Но мне для школьников-студней надо.
bit_cast — вот прям самое оно!
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re: Это UB ?
От: vsb Казахстан  
Дата: 01.07.24 15:59
Оценка: 4 (2)
Здравствуйте, LaptevVV, Вы писали:

LVV>А сейчас ?

LVV>Где-то у меня в мозгах зацепилось, что это UB.

И сейчас UB. Хотя, наверное, работать везде будет. Но по правилам — в юнионах можно читать только те поля, куда ранее была запись.

LVV>Размещающий new — не предлагать

LVV>reinterpret_cast — можно попробовать.

LVV>variant ?

LVV>Что-то не совсем то, что мне нужно.

Могу ошибаться, но вроде можно прикастовать int* к char* (но не наоборот). В С это должно работать, насчёт С++ не уверен. Тут, правда, тоже нюансы могут быть типа сколько там байтов в int и сколько битов в char — тоже величины не определённые.

А так — 100% правильный вариант это битовая арифметика. Хороший компилятор должен распознать замысел и преобразовать всё в ожидаемый код.

Вот пример с godbolt:

void u32to8(uint32_t u32, uint8_t *u8) {
    u8[0] = u32 & 0xff;
    u8[1] = (u32 >> 8) & 0xff;
    u8[2] = (u32 >> 16) & 0xff;
    u8[3] = (u32 >> 24) & 0xff;
}


Это скомпилировалось в

u32to8(unsigned int, unsigned char*):
        str     r0, [r1]  @ unaligned
        bx      lr
main:


То бишь в одну инструкцию. А когда компилятор это инлайнит по месту вызова, там вообще ничего не остаётся.
Отредактировано 01.07.2024 16:00 vsb . Предыдущая версия .
Re[2]: Это UB ?
От: T4r4sB Россия  
Дата: 01.07.24 17:07
Оценка: -2 :)
Здравствуйте, vsb, Вы писали:

vsb>Здравствуйте, LaptevVV, Вы писали:


LVV>>А сейчас ?

LVV>>Где-то у меня в мозгах зацепилось, что это UB.

vsb>И сейчас UB. Хотя, наверное, работать везде будет. Но по правилам — в юнионах можно читать только те поля, куда ранее была запись.


На чары не распространяется правило strict aliasing
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[3]: Это UB ?
От: vsb Казахстан  
Дата: 01.07.24 17:19
Оценка: +2
Здравствуйте, T4r4sB, Вы писали:

LVV>>>А сейчас ?

LVV>>>Где-то у меня в мозгах зацепилось, что это UB.

vsb>>И сейчас UB. Хотя, наверное, работать везде будет. Но по правилам — в юнионах можно читать только те поля, куда ранее была запись.


TB>На чары не распространяется правило strict aliasing


https://en.cppreference.com/w/cpp/language/union

It is undefined behavior to read from the member of the union that wasn't most recently written

Кроме того

The details of that allocation are implementation-defined

То бишь теоретически ничего не мешает компилятору понавставлять каких-нибудь паддингов, если ему так захочется.
Re[4]: Это UB ?
От: T4r4sB Россия  
Дата: 01.07.24 17:43
Оценка:
Здравствуйте, vsb, Вы писали:

vsb>То бишь теоретически ничего не мешает компилятору понавставлять каких-нибудь паддингов, если ему так захочется.


Это было бы implementation-defined
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[3]: Это UB ?
От: Pzz Россия https://github.com/alexpevzner
Дата: 01.07.24 19:57
Оценка: 3 (1) -2
Здравствуйте, LaptevVV, Вы писали:

LVV>Очень интересно!

LVV>Но мне для школьников-студней надо.
LVV>bit_cast — вот прям самое оно!

Вот и вырастут у тебя студенты, которые думают, что bit_cast — это хитрая волшебная магия, которая делает хитрое волшебное преобразование, и написана она хитрыми волшебными волшебниками, чей ход мысли простому человеку не понять.

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

В результате мы получаем специалиста, который вместо того, чтобы усвоить блок фундаментальных знаний, кстати, в программировании довольно компактный и поддающийся усвоению за конечное время, пытается впихнуть в свою голову невпихуемое, а именно, достаточно детальное знание модных на настоящий момент фреймворков и библиотек. Что чрезвычайно повышает порог вхождения в профессию, причем без особой на то нужды. Кроме того, поддержание себя в "профессиональном тонусе" с точки зрения такого специалиста включает в себя слежение за переменчивой модой в области популярных фреймворков и библиотек и изучение новых по мере вхождения их в оборот, что отнимает массу сил и времени, опять же, без особой на то нужды.
Re[2]: Это UB ?
От: Pzz Россия https://github.com/alexpevzner
Дата: 01.07.24 20:01
Оценка:
Здравствуйте, vsb, Вы писали:

LVV>>Где-то у меня в мозгах зацепилось, что это UB.


vsb>И сейчас UB. Хотя, наверное, работать везде будет. Но по правилам — в юнионах можно читать только те поля, куда ранее была запись.


Сейчас компиляторы пошли хитрые. Заметив в твоей программе UB, он может вообще что угодно сделать. Причем не в том месте, где UB, а где сам захочет. Например, может счесть, что 2 + 2 == 5, или подсыпать слабительного в миску с кормом твоего кота.
Re[3]: Это UB ?
От: T4r4sB Россия  
Дата: 01.07.24 20:21
Оценка:
Здравствуйте, Pzz, Вы писали:

Pzz>Сейчас компиляторы пошли хитрые. Заметив в твоей программе UB, он может вообще что угодно сделать. Причем не в том месте, где UB, а где сам захочет. Например, может счесть, что 2 + 2 == 5, или подсыпать слабительного в миску с кормом твоего кота.


Это если UB воспринимать как чёрную магию.
А на самом деле оптимизатору надо знать, в каких случаях не надо делать лишнее чтение из памяти. И придуманы всякие хитрые правила для этого.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[4]: Это UB ?
От: Pzz Россия https://github.com/alexpevzner
Дата: 01.07.24 22:20
Оценка: +3
Здравствуйте, T4r4sB, Вы писали:

Pzz>>Сейчас компиляторы пошли хитрые. Заметив в твоей программе UB, он может вообще что угодно сделать. Причем не в том месте, где UB, а где сам захочет. Например, может счесть, что 2 + 2 == 5, или подсыпать слабительного в миску с кормом твоего кота.


TB>Это если UB воспринимать как чёрную магию.

TB>А на самом деле оптимизатору надо знать, в каких случаях не надо делать лишнее чтение из памяти. И придуманы всякие хитрые правила для этого.

Дело не в черной магии. Мне сам подход не очень нравится. Да, компиляторы, генерирующие эффективный код, нужны. Но правила игры стали столь сложными, что даже очень квалифицированному человеку трудно учесть все нюансы.

Во многих случаях лучше иметь предсказуемое, понятное поведение, чем сэкономить пару циклов процессора. Даже в очень высоконагруженных программах, работающих на пределе требований по эффективности код, реально требующий сверхэффективной оптимизации, редко составляет более 10% общей кодовой базы программы. Причем в хорошо спроектированной программе сложный код и быстрый код редко пересекаются.

И на мой взгляд, было бы лучше, чтобы компилятор помогал делать сложный код более предсказуемым, а не быстрый код более быстрым. Возможно, чем усложнять правила игры везде, следовало бы добавить явную ручку, позволяющую сказать компилятору, "вот в этом месте, пожалуйста, побыстрее, даже за счет усложнения". Но по умолчанию держать эту ручку выключенной.
Re[4]: Это UB ?
От: LaptevVV Россия  
Дата: 02.07.24 09:38
Оценка:
LVV>>Очень интересно!
LVV>>Но мне для школьников-студней надо.
LVV>>bit_cast — вот прям самое оно!видно чела с фундаментальной ап
Pzz>Вот и вырастут у тебя студенты, которые думают, что bit_cast — это хитрая волшебная магия, которая делает хитрое волшебное преобразование, и написана она хитрыми волшебными волшебниками, чей ход мысли простому человеку не понять.
Под капотом я все рассказываю
И дополнительный код для целых, и сдвиги вместо деления, и замену вычитания сложением сдопкодом и т.д.
Мне именно для подкапотом надо безопасно плавающее в биты разложить.
Без уб и прочих разных гадостей.

Pzz>В результате мы получаем специалиста, который вместо того, чтобы усвоить блок фундаментальных знаний, кстати, в программировании довольно компактный и поддающийся усвоению за конечное время, пытается впихнуть в свою голову невпихуемое, а именно, достаточно детальное знание модных на настоящий момент фреймворков и библиотек. Что чрезвычайно повышает порог вхождения в профессию, причем без особой на то нужды. Кроме того, поддержание себя в "профессиональном тонусе" с точки зрения такого специалиста включает в себя слежение за переменчивой модой в области популярных фреймворков и библиотек и изучение новых по мере вхождения их в оборот, что отнимает массу сил и времени, опять же, без особой на то нужды.


мОлодежь, как это сейчас у них принято, вопрошает: а нафига все это нужно?
И только по прошествии нескольких лет работы признаются (мне выпускники говорили), что становится видно чела с фундаментальной подготовкой и без оной.
И первые — лучшие работники, чем вторые...
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re: Это UB ?
От: ajanov  
Дата: 02.07.24 09:56
Оценка: +1
Здравствуйте, LaptevVV, Вы писали:

LVV>Создаем union

LVV>
union D{
LVV>int a;
LVV>char b[4];     // или std::byte b[4]
LVV>};
LVV>D temp;
LVV>temp.a = 1234;
LVV>char byte = temp.b[0];
LVV>

LVV>В прежние времена — делалось так.
LVV>А сейчас ?
LVV>Где-то у меня в мозгах зацепилось, что это UB.

LVV>Размещающий new — не предлагать

LVV>reinterpret_cast — можно попробовать.

LVV>variant ?

LVV>Что-то не совсем то, что мне нужно.

В C — не UB, в C++ — UB начиная с C++11, но на x86 работает, по крайней метре MSVC и GCC, имеется легаси, которое может выдать сюрприз при обновлении компилятора. Для манипуляций с типами через битовое представление нужно использовать reinterpret_cast или std::bit_cast (с C++20). Последний учитывает особенности выравнивания.
В любом случае с такими манипуляциями программа перестает быть переносимой. Нужно получить представление целого побайтно от младшего к старшему? — то так:

void foo(uint32_t x, std::uint8_t out[4])
{
    out[0] = x & 0x000000FF;
    out[1] = (x & 0x0000FF00) >> 8;
    out[2] = (x & 0x00FF0000) >> 16;
    out[3] = (x & 0xFF000000) >> 24;
}
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.