Переинтерпретировать_приведение __uint128_t

Насколько я знаю, reinterpret_cast не должен приводить к потере данных.

Таким образом, такой код невозможно скомпилировать в X86_64, поскольку целое число меньше указателя.

#include <cstdio>
int main() {
    int a = 123;
    int res = reinterpret_cast<int>(reinterpret_cast<void*>(a));
    printf("%d", a == res);
}

Вопрос: почему я могу компилировать такой код в GCC и Clang?

#include <cstdio>
int main() {
    __uint128_t a = 4000000000000000000;
    a *= 100;
    __uint128_t res = reinterpret_cast<__uint128_t>(reinterpret_cast<void*>(a));
    printf("%d", a == res);
}

И результат, который я получаю, "0", означает, что есть потеря данных.

Редактировать

Я думаю, что есть 3 возможных варианта, что это может быть. Ошибка компилятора, злоупотребление спецификацией или следствие спецификации. Какой это?

Заранее и хорошо изучите, что неопределенное поведение существует, и просто возможность скомпилировать/запустить что-то не означает, что это допустимый или безопасный код C++. reinterpret_cast просто сообщает компилятору: «Я думаю, что знаю, что делаю, так что позвольте мне это сделать», но четко документировано, какие приведения на самом деле допустимы, и компилятор не помешает вам сделать те, которые недействительны.

underscore_d 23.12.2020 18:48

@underscore_d Я думаю, что reinterpret_cast определенно защищает вас в некоторых случаях. Мне интересно, почему это не делается сейчас.

CPPCPPCPPCPPCPPCPPCPPCPPCPPCPP 23.12.2020 18:59

у вас просто есть 8 старших байтов или около того. это как mov ax , WORD PTR some_dword в масме

Алексей Неудачин 23.12.2020 20:10

@CPPCPPCPPCPPCPPCPPCPPCPPCPPCPP reinterpret_cast must not lead to data loss Думаю, вы неправильно это прочитали, и это не единственный случай, когда это может произойти.

dxiv 23.12.2020 21:27

@dxiv Можете ли вы показать другие случаи с reinterpret_cast? Я не нашел много.

CPPCPPCPPCPPCPPCPPCPPCPPCPPCPP 23.12.2020 21:29

@CPPCPPCPPCPPCPPCPPCPPCPPCPPCPP Может быть, не «потеря данных» как таковая, но стандарт отмечает , что «отображение, выполненное reinterpret_­cast, может или не может давать представление, отличное от исходного значения». Один пример из cppreference.com заключается в том, что «один и тот же указатель может иметь несколько целочисленных представлений», что на самом деле довольно часто встречается в архитектурах со смещением сегментов.

dxiv 23.12.2020 23:21
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
6
253
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Это объясняется здесь https://en.cppreference.com/w/cpp/language/reinterpret_cast

  1. Указатель можно преобразовать в любой целочисленный тип, достаточно большой, чтобы вместить все значения этого типа (например, в std::uintptr_t).

Вот почему у вас есть ошибка для первого случая

  1. Значение любого интегрального или перечисляемого типа может быть преобразовано в тип указателя...

вот почему у вас нет ошибки, но во втором случае она переносится на 0. он каким-то образом предполагает, что тип указателя имеет самый большой диапазон по сравнению с любыми целочисленными типами, тогда как со 128-битными целыми числами это не так.

Обратите внимание, что 128-битное целое число, вообще говоря, не является целочисленным типом, но, по крайней мере, gcc определяет его как в расширениях gcc:

от https://quuxplusone.github.io/blog/2019/02/28/is-int128-integral/

libstdc++ (в стандартном режиме, отличном от gnu++XX) оставляет is_integral_v<__int128> как false. Это имеет определенный смысл с точки зрения разработчика библиотеки, потому что __int128 не является одним из стандартных целочисленных типов, и, кроме того, если вы называете его целочисленным, то вы должны столкнуться с тем следствием, что intmax_t (который составляет 64 бита на каждый ЛПИ, который имеет значение) как бы лжет о том, что он «максимум».

но

В режиме -std=gnu++XX libstdc++ делает is_integral_v<__int128> равным true

Но void* не может содержать значение __uint128_t. У меня нет исходного значения, как вы видите во втором примере. Если бы значение было оригинальным, printf выдал бы «1».

CPPCPPCPPCPPCPPCPPCPPCPPCPPCPP 23.12.2020 18:40

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

Jean-François Fabre 23.12.2020 18:45

На самом деле эта часть выглядит как решение: (обратное преобразование в обратном направлении не гарантируется; один и тот же указатель может иметь несколько целочисленных представлений). Что немного сбивает с толку, я думаю, что это правильное мнение, что разработчики компилятора предполагают, что Тип указателя самый большой.

CPPCPPCPPCPPCPPCPPCPPCPPCPPCPP 23.12.2020 18:48

В основном я не понимаю, является ли это ошибкой компилятора, злоупотреблением спецификацией или следствием спецификации.

CPPCPPCPPCPPCPPCPPCPPCPPCPPCPP 23.12.2020 18:52

@CPPCPPCPPCPPCPPCPPCPPCPPCPPCPP Спецификация говорит, что любое целое число может быть преобразовано в указатель, так что это следствие спецификации.

Mooing Duck 23.12.2020 19:02

@CPPCPPCPPCPPCPPCPPCPPCPPCPPCPP Это практически никогда не ошибка компилятора, это разумное предположение для языковых функций, которым уже несколько десятилетий. Совершенно новые функции C++ страдают от ошибок компилятора и библиотеки и даже от ошибок (кхм, недостатков) в стандарте. Но эти слепки в том виде, в каком вы их используете, уже давно устарели.

Kuba hasn't forgotten Monica 23.12.2020 19:34

Ваша вторая цитата неприменима. __uint128_t не является "интегральным типом".

Jeff Garrett 23.12.2020 22:27

нет, не в целом, но в расширении gcc это так, см. мое редактирование (во всяком случае, хороший момент)

Jean-François Fabre 23.12.2020 22:37

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