Каков переносимый способ приведения к символу и обратно, сохраняя тот же битовый шаблон?

Многие методы принимают char за «байтовый тип» 1. Однако неясно (для меня), является ли поведение, определяемое реализацией, то, что должно делать приведение от unsigned char к char, когда значение unsigned char больше, чем CHAR_MAX.

Этот раздел взят из C++11 (ISO/IEC 14882:2011) §4.7 Интегральные преобразования [conv.integral/2]:

Если тип назначения подписан, значение не изменяется, если оно может быть представлено в типе назначения (и ширине битового поля); в противном случае значение определяется реализацией.

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

Итак, как мне привести uint8_t, unsigned char или другой тип ширины символа к char и обратно, сохраняя битовый шаблон?

Примечание. Этот вопрос касается C++ в целом, а не конкретной версии. Если что-то было неприемлемо в C++11, но работало в C++14, то было бы полезно, если бы ответ мог противопоставить две версии.

1: например, встроенные функции SIMD x64, такие как __m128i _mm_set1_epi8(char), используйте char.

Приведение между знаковыми и беззнаковыми типами одного и того же размера не меняет битовую комбинацию благодаря дополнению 2.

Jason 07.06.2024 17:11

Цитата, о которой вы говорите, предназначена для преобразований, т. е. signed char foo = unsigned_vchar_vat Выполнение conat char * data = &unsigned_variable позволяет вам проверять байты unsigned_variable.

NathanOliver 07.06.2024 17:13

@Jason Если вы можете процитировать, что стандарт гарантирует переносимость, вы можете опубликовать это как ответ.

doliphin 07.06.2024 17:15

@NathanOliver Если вы считаете, что это рекомендуемый (и указанный) способ преобразования с сохранением битового шаблона (т. е. *(unsigned char *)&ch или что-то подобное), это ответ.

doliphin 07.06.2024 17:16

Я не думаю, что это включено в стандарт, потому что C++ должен работать на машинах, не имеющих дополнительных процессоров. Многие из них вы больше не найдете, и беспокоиться о них — это суперпедантично.

Jason 07.06.2024 17:20

@Джейсон, тебе даже не гарантировано, сколько бит в типе char. Беспокойство по поводу странной архитектуры может показаться педантичным до тех пор, пока вы не будете вынуждены делать это ради своей работы.

Mark Ransom 07.06.2024 17:25

@MarkRansom, вам гарантировано, что char и unsigned char имеют одинаковое количество бит. В стандарте это не указано, но даже на машинах с дополнением, отличным от 2, приведения здесь не меняют биты, если только реализация не является намеренно тупой.

Caleth 07.06.2024 17:28

@Джейсон Это было изменено в C++20. Все целочисленные типы теперь должны дополняться двумя.

NathanOliver 07.06.2024 17:30

@MarkRansom Если вы обобщаете процессоры, которые не являются 8-битными символами, это абсурдно педантично. Я работаю в мире встроенных систем и видел больше странных архитектур, чем большинство других. Я никогда не видел процессора, в котором не было бы 8-битных символов и дополнения до 2.

Jason 07.06.2024 17:35
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
9
112
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В C++20 вы можете использовать std::bit_cast. Это гарантирует, что вы получите побитовое идентичное значение для типов без битов заполнения, которыми являются char и unsigned char.

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

Формулировка в стандарте существует, потому что битовые комбинации, соответствующие отрицательным числам, представляют разные числа в дополнении до двух, дополнении до единицы, а также знаке и величине.

В противном случае вы можете std::memcpy lvalue unsigned char в lvalue char

  1. Даже если платформа не является дополнением до двух, нет смысла менять битовую комбинацию при приведении знака <-> без знака. В итоге вы можете получить -0, и в итоге вы получите значение, отличное от того, которое дала бы машина с дополнением до двух, но если реализация не изо всех сил старается быть тупой, она будет иметь тот же битовый шаблон.

Нет ли четкого способа приведения битов unsigned char к char до C++20?

doliphin 07.06.2024 17:17

@doliphin всегда есть memcpy

Caleth 07.06.2024 17:21

@Калет, это достойно еще одного ответа.

Mark Ransom 07.06.2024 17:26

@MarkRansom Я углубился в подробности.

Caleth 07.06.2024 17:36

Причина, по которой memcpy работает, заключается в том, что он даже не предполагает копирования типа char, он принимает void* параметры. Это настолько чистая копия памяти, насколько это возможно в C/C++.

Mark Ransom 07.06.2024 17:44
std::bit_cast — надгробие memcpy. Все варианты использования memcpy покрываются безопасными и эффективными стандартными функциями, начиная с C++20. memcpy имеет множество предостережений и подводных камней, что делает использование кода подверженным ошибкам. Единственным оставшимся вариантом использования до C++20 была игра слов типов (как в OP). memcpy вызовы должны генерироваться компилятором или реализацией стандартной библиотеки. Пользовательский код C++, содержащий прямые вызовы этой функции, вызывает тревогу. Предпочитайте std::bit_cast, если можете переключиться на C++20 или выше.
Red.Wave 08.06.2024 19:06

Другие вопросы по теме