байты внутри живого объекта?
Единственное, я бы оперировал unsigned char, вместо uint8_t
По определению strict aliasing https://en.cppreference.com/w/c/language/object
Есть: этого нельзя делать в настоящий момент.
P1839R0: Accessing Object Representations (by Krystian Stasiowski) (2019-08-09) (Related: GitHub issue) P1839R1: Accessing Object Representations (by Krystian Stasiowski) (2019-10-02) (Related: GitHub issue) P1839R2: Accessing Object Representations (by Krystian Stasiowski) (2019-11-20) (Related: GitHub issue) P1839R3: Accessing Object Representations (by Krystian Stasiowski, Timur Doumler) (2022-02-19) (Related: GitHub issue) P1839R4: Accessing Object Representations (by Krystian Stasiowski, Timur Doumler) (2022-03-16) (Related: GitHub issue) P1839R5: Accessing object representations (by Timur Doumler, Krystian Stasiowski) (2022-06-17) (Related: GitHub issue)
То есть, тасовать байты нельзя, а заполнить uint32_t через memset можно? uint32_t data = 0; memset(&data, 0x42, sizeof(data));
Заполнение через memset() - серая зона. Можно считать, полагаю, что это исключение для стандартной библиотеки. Сишное наследие слабо покрывается крестовым нормативом, обычно там просто пишут, что "контракты такие же, как в C", с пренебрежением к тому, что модели различаются.
А в изначальном примере UB что-ли?
А как тогда поменять местами байты внутри uint32_t?
Никак, полагаю =)
Вы историю вопроса читали вообще?
Потенциально можете создать новый объект с таким значением.
Так а значение как получить? Ведь мне исходные данные в рантайме придут
as_bytes можно попробовать, опять же, полагаясь на библиотечное исключение. Что примечательно, нормативное описание этих примитивов по сути означает, что осмысленно пользоваться ими нельзя. Надо бы посмотреть issue по этому поводу, наверное...
это нужно делать аккуратно, идеально покрыть тестами, чтобы код работал как ты это задумал. А так, тут запрета нет, как обрабатывать биты, хоть массив, хоть каст в структуру, хоть onion, портянка из сдвигов
Написать менялку через сдвиги и &, компилятор поймет и сделает все, что нужно, коротким путем.
В этом примере все аккуратно. Все тесты проходят. Однако это UB 😂
Не понял из документа следующий момент в этом примере: using T = unsigned char*; int a = 0; T b = reinterpret_cast<T>(&a); // Pointer value unchanged, still // points to the int object T c = ++b; // UB, expression type differs // from element type Почему здесь UB? Мы сказали, что b - это указатель на unsigned char. Далее мы его инкрементим и его значение присваиваем другой переменной того же типа. Почему UB?
Выполняя реинтерпретацию мы всего лишь подправляем тип выражения: сам указатель от этого указывать на a не перестает - это тема provenance'ов и, в частности, std::launder() как раз.
Макросами или constexpr, чтобы делегировать подтасовку на preprocessing-time/compile-time
https://godbolt.org/z/h3b48TsKc вот, прячешь функцию в какой нибудь хидер и никто не заметит что ты ниггадяй, а главное ноги твоей функцией не отстрелит
в том примере даже не разыменовывается ничего выражение T c = ++b; где b и c это указатели типа T, по-моему всегда валидно, пока ++b не заходит за past-the-end
https://godbolt.org/z/4jT5Ms4s8 вот, в точке вызова никто твои магические упражнения и не заметит
а тут ты главный, чего, боишься компилятора? Ну можешь копировать побайтово сдвигом и делать без каста, но и тут компилятор не ругается, все хорошо
После приведенных документов выглядит как наброс на вентилятор и троллинг
> не заходит за past-the-end Но past-the-end чего?) Резюмирую пример: int i{}; reinterpret_cast<byte*>(&i) + 1; Этого уже достаточно для неопределенного поведения по определению арифметики указателей (нет подлежащего массива). Поскольку e[i] == *(e + i), с индексацией такая же проблема.
не увидел документов касающихся типа int и его производных
вы упускаете http://eel.is/c++draft/basic.compound#3.sentence-12
Уточните, что считаете релевантным там. По моим представлениям оно всего лишь про: T a[n] -> T a[n + 1]; T a -> T a[2]; (где последний элемент "гипотетический" и получать доступ к нему нельзя - только сравнивать и перемещаться)
А, хотя я понял, кажется, Вашу мысль здесь: Вы имеете в виду, что int i; reinterpret_cast<byte*>(&i) + 1 /* #1 */; как раз должно быть можно и в #1 результат должен указывать на past-the-end для int исключительно за счет того, что прибавляется именно единица? =) Да, формально Вы должны быть правы, в таком случае, но думаю, что это - очередная дыра в себе (поскольку адресно результат будет другим: расчет ведь по ct-типу).
так речь не о гипотетическом типе T, а о uint32_t, устройство которого нам достоверно известно. Тогда и char[] - это уб, ну мы же МОЖЕМ выйти за пределы массива
скорее всего я не прав, потому что как вы правильно заметили, формально там нет не то что массива, и но и объекта типа unsigned char
Вы, вероятно, упускаете суть беседы. Уточните, что именно не понимаете и в чем видите здесь аналогию с char[].
Главный вопрос - а нафига вручную reverse писать, есть же готовые функции.
Ну цитируемое должно быть справедливо, но составлять issue смысла не вижу: такие противоречия, как я понял, признаются и обрабатываются неохотно, особенно с учетом того, что с принятием 1839 (которое пока не предвидится, как я понимаю), смысл оно вовсе потеряет скорее всего.
Sergey, касательно этого Вашего ответа. Как описано в моем изначальном примере делать нельзя, это UB. Я переписал функцию reverse. Скажите, теперь в ней есть UB?
А где именно?
На моменте memcpy последнего
Вот тут: std::memcpy(&value, buff, size); ?
Так, опять поломка старых знаний... Вроде как заполнять объект через memcpy можно. Тем более тривиальный тип.
А если ограничить тривиальными?
я бы сказал только фундаментальными типами
Вопрос - а зачем именно через временный буфер, хочется "универсальности" ?
А есть трейт для этого?
Битовые операции
Код будет гораздо сложнее тогда.
Так а зачем, если приведенный более понятен, делает то же самое и в нем нет ub?
А может всё-таки trivially_copyable?
В отношении memcpy() есть всего два специальных разрешения (1, 2), которые относятся к Вашему примеру и все-таки не покрывают. В остальном, норматив ссылается на С-стандарт, который на настоящий момент описывает memcpy() так: > The memcpy function copies n characters from the object pointed to by s2 into the object pointed to by s1. If copying takes place between objects that overlap, the behavior is undefined. Как это транслируется в крестовую объектную модель - shrug: по моему представлению, в этом отношении объектная модель underspecified.
Обсуждают сегодня