С ++ 20 bit_cast против reinterpret_cast

Согласно последнему заседанию комитета ISO C++, битовый будет введен в стандарт C++ 20.

Я знаю, что reinterpret_cast не подходит для этой работы из-за правила псевдонима типов, но мой вопрос в том, почему они решили не расширять reinterpret_cast, чтобы рассматривать объект как представление битовой последовательности, и предпочли предоставить эту функциональность как новую языковую конструкцию?

Каким образом вы предлагаете расширить reinterpret_cast? То есть, как бы гипотетически выглядел код, использующий это?

Nicol Bolas 20.11.2018 22:23

@NicolBolas: Как насчет того, чтобы позволить reinterpret_cast делать это: float x = 1.0f; reinterpret_cast<unsigned int>(x);.

geza 20.11.2018 22:29

Я думал в точности так, как предложил @geza

bogdan tudose 20.11.2018 22:34

@geza: reinterpret_cast уже имеет определенное значение для этого, так что это изменит семантику reinterpret_cast, а не расширяет ее.

Chris Dodd 22.05.2019 07:00

@ChrisDodd: Я не думаю, что это правда. Какое значение это имеет в настоящее время?

geza 22.05.2019 09:58

@geza reinterpret_cast<unsigned>(1.0f) == 1U; - выполняет преобразование типа float-> int.

Chris Dodd 22.05.2019 20:21

@ChrisDodd: нет, это преобразование в настоящее время плохо сформировано.

geza 22.05.2019 21:00

На самом деле это было давным-давно предложенный.

Davis Herring 09.03.2021 17:14
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
49
8
8 035
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Что ж, есть одна очевидная причина: потому что он не будет делать все, что делает bit_cast. Даже в мире C++ 20, где мы можем выделять память во время компиляции, reinterpret_cast запрещен в функциях constexpr. Одна из явных целей bit_cast - иметь возможность делать такие вещи во время компиляции:

Furthermore, it is currently impossible to implement a constexpr bit-cast function, as memcpy itself isn’t constexpr. Marking the proposed function as constexpr doesn’t require or prevent memcpy from becoming constexpr, but requires compiler support. This leaves implementations free to use their own internal solution (e.g. LLVM has a bitcast opcode).

Теперь вы можете сказать, что можете просто расширить это конкретное использование reinterpret_cast на контексты constexpr. Но это усложняет правила. Вместо того, чтобы просто знать, что reinterpret_cast нельзя использовать в период кода constexpr, вы должны помнить конкретные формы reinterpret_cast, которые нельзя использовать.

Также есть практические проблемы. Даже если вы хотите пойти по пути reinterpret_cast, std::bit_cast - это библиотечная функция. И всегда легче получить функцию библиотеки через комитет, чем функцию языка, даже если она получит некоторую поддержку компилятора.

Тогда есть более субъективные вещи. reinterpret_cast обычно считается опасной по своей сути операцией, что свидетельствует о некотором "обмане" системы типов. Напротив, bit_cast - нет. Он создает новый объект, как будто копируя его представление значения из существующего. Это низкоуровневый инструмент, но он не мешает работе системы типов. Поэтому было бы странно писать «безопасную» операцию так же, как «опасную».

В самом деле, если вы написали их таким же образом, это начнет вызывать вопросы, почему это достаточно четко определено:

float f = 20.4f;
int i = reinterpret_cast<int>(f);

Но это как-то плохо:

float f = 20.4f;
int &i = reinterpret_cast<int &>(f);

И, конечно же, юрист по языку или кто-то, кто знаком со строгим правилом псевдонима, поймет, почему последнее плохо. Но для непрофессионала, если использование reinterpret_cast для преобразования битов нормально, неясно, почему неправильно использовать reinterpret_cast для преобразования указателей / ссылок и интерпретации существующего объекта как преобразованного типа.

Разные инструменты следует писать по-разному.

Вторая из ваших последних форм должна быть определена в тех случаях, когда все использование i происходит до следующего обращения к хранилищу или обращения к нему конфликтным образом (записи конфликтуют с чтениями или записями; чтения не конфликтуют с чтениями) с помощью средств, не полученных из i, или выполнение достигает начала функции или тела истинного цикла, в котором это произойдет. Правило «Строгое наложения» было предназначено для того, чтобы не требовать от компиляторов пессимистичного отношения к вещам, которые они не видят, а не для того, чтобы побуждать их игнорировать то, что они могут.

supercat 23.05.2019 16:42

Что касается «reinterpret_cast обычно считается опасной по своей сути операцией» ... Я думаю, это не объясняет, вероятно, наиболее распространенный вариант использования reinterpret_cast, который я вижу, что-то вроде reinterpret_cast<unsigned char *>(ptr). Это не более опасная или «обманчивая» система типов, чем static_cast<unsigned char *>(static_cast<void *>(ptr)).

user541686 21.11.2021 10:13

@ user541686: Это также запрещено в коде constexpr. Вы можете constexprbit_cast в байтовый массив. И нет, это не опаснее; это просто дольше.

Nicol Bolas 21.11.2021 15:17

Существует фундаментальное несоответствие между современной строгой интерпретацией языковых стандартов C и C++ компиляторами в высокоуровневой языковой природе и представлением о том, что вы можете использовать reinterpret_cast для переинтерпретации группы байтов как других объектов. Обратите внимание, что так называемое правило «строгого псевдонима» в большинстве случаев не может даже использоваться для дисквалификации любой попытки переинтерпретации байтов, поскольку код изначально не определял бы поведение: reinterpret_cast<float*>(&Int) даже не является указателем на объект с плавающей запятой, это указатель на целое число неправильного типа. Вы не можете разыменовать его, поскольку в этом месте не создан объект типа float; если бы он был, его жизнь не началась бы; и если бы его время жизни началось, оно было бы неинициализированным.

Байты, которые представляют собой действительный образец битов с плавающей запятой, просто не могут быть интерпретированы как таковые, если у вас нет здесь подходящего объекта с плавающей запятой.

Допустимый ненулевой указатель - это не просто типизированное значение начального адреса области, которая оказывается правильно выровненной; ненулевой действительный указатель указывает на конкретный объект (или один за концом массива или тривиальный «массив» одного объекта).

Я даже не вижу санкционированных "строгих псевдонимов" приведений скалярной переинтерпретации (смесь со знаком / без знака) как возможно допустимые, поскольку по этому адресу существует целочисленный объект без знака (соответственно, без знака) (и компилятор, очевидно, не может использовать беззнаковый (соответственно . подписано) исходное значение тоже).

В любом случае, C++ имеет неправильный дизайн, потому что он представляет собой смесь разных языков (некоторые очень низкого уровня, некоторые очень высокого уровня) и сильно сломан.

"так называемое правило "строгого псевдонима" в большинстве случаев не может использоваться даже для дисквалификации любой попытки переинтерпретации байтов, поскольку код изначально не определял бы поведение" ... что? Это правило строгого псевдонима, что причины этот код должен быть UB. Без этого правила стандарт был бы неполным, потому что не было бы утверждения о его поведении. Есть разница между «это UB» и «стандарт в этой области не определен».

Nicol Bolas 23.05.2019 17:10

@NicolBolas Кто сказал, что стандартная инструкция должна быть полной? Как он сейчас завершен? Что в любом случае означает разыменование указателя reinterpret_casted? Если транслировать на char* можно, то почему не на short* или float*? Если можно использовать традиционно memcpy, а недавно - bit_cast, почему нельзя разыменовать приведенный указатель?

curiousguy 23.05.2019 23:03

@NicolBolas В C, где определяется поведение memcpy одним FILE по сравнению с другим? Все ли вызовы memcpy полностью определены или явно сделаны UB?

curiousguy 24.05.2019 21:14

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