C ++: Почему интерпретация присваивания значения всегда int?

Я хотел бы присвоить значение переменной, как это:

double var = 0xFFFFFFFF;

В следствии var получает значение 65535.0 Поскольку компилятор предполагает 64-битную целевую систему, числовой литерал (то есть все соответствующие 32 бита) интерпретируется как значащие и точные биты. Тем не менее, так как 0xFFFF FFFF это просто обозначение для битового шаблона, без какого-либо намека на представление, это может быть совершенно по-разному интерпретировано w.r.t. становится значением с плавающей запятой. Таким образом, мне было интересно, есть ли способ манипулировать этой фиксированной интерпретацией значения. Другими словами, дать подсказку о желаемом представлении. (Возможно, кто-то мог бы также указать мне, чтобы я участвовал в стандарте, где определена эта неявная интерпретация).

Пока что точность интерпретации по умолчанию в моей системе

(int) 0xFFFFFFFF x 100.

введите описание изображения здесь
Заполняется только поле дроби1.

Поэтому, возможно (здесь: для 16-битной кросс-компиляции) я хочу, чтобы это было другое представление, подобное:

(int) 0xFFFFFF x 10(Целое) 0xFF

(игнорируя знак бит на мгновение).

Таким образом, мой вопрос: как я могу заставить пользовательскую двойную интерпретацию шестнадцатеричной литеральной записи?


1 Даже когда мой шестнадцатеричный литерал будет 0xFFFF FFFF FFFF FFFF значение интерпретируется только как часть дроби — поэтому ясно, что биты должны использоваться для поля экспоненты и знака. Но кажется, что буквальное просто отрезано.

1

Решение

C ++ не определяет представление в памяти для doubleБолее того, он даже не определяет представление целочисленных типов в памяти (и может действительно отличаться в системах с разными окончаниями). Так что если вы хотите интерпретировать байты 0xFF, 0xFF как doubleВы можете сделать что-то вроде:

uint8_t bytes[sizeof(double)] = {0xFF, 0xFF};
double var;
memcpy(&var, bytes, sizeof(double));

Обратите внимание, что с помощью союзов или reinterpret_castСтрого говоря, указатели — это неопределенное поведение, хотя на практике это тоже работает.

3

Другие решения

«Мне было интересно, есть ли способ манипулировать этой интерпретацией».

Да, вы можете использовать reinterpret_cast<double&> через адрес, чтобы вызвать (пере) интерпретацию типа из определенной битовой комбинации в памяти.

«Таким образом, мой вопрос: как я могу заставить двойную интерпретацию шестнадцатеричной записи?»

Вы также можете использовать объединение, чтобы сделать его более понятным:

union uint64_2_double {
uint64_t bits;
double dValue;
};

uint64_2_double x;
x.bits = 0x000000000000FFFF;

std::cout << x.dValue << std::endl;
3

Кажется, не существует прямого способа инициализации double переменная с шестнадцатеричным шаблоном, приведение в стиле c эквивалентно C ++ static_cast и reinterpret_cast будет жаловаться, что не может выполнить преобразование. Я дам вам два варианта, одно простое решение, но оно не будет инициализировать непосредственно переменную, и сложное. Вы можете сделать следующее:

double var;
*reinterpret_cast<long *>(&var) = 0xFFFF;

Примечание: обратите внимание, что я ожидаю, что вы захотите инициализировать все 64 бита double, ваша константа 0xFFFF кажется маленькой, она дает 3.23786e-319

Литеральное значение, начинающееся с 0x, представляет собой шестнадцатеричное число типа unsigned int. Вы должны использовать суффикс ul, чтобы сделать его литералом unsigned long, что в большинстве архитектур будет означать 64-битное unsigned; или же, #include <stdint.h> и сделать, например, uint64_t(0xABCDFE13)

Теперь о сложных вещах: в старом C ++ вы можете запрограммировать функцию, которая преобразует целочисленную константу в двойную, но это не будет constexpr,

В constexpr функции, которые вы не можете сделать reinterpret_cast, Тогда, единственный способ сделать двойной конвертер constexpr — использовать объединение посередине, например:

struct longOrDouble {
union {
unsigned long asLong;
double asDouble;
};
constexpr longOrDouble(unsigned long v) noexcept: asLong(v) {}
};

constexpr double toDouble(long v) { return longOrDouble(v).asDouble; }

Это немного сложно, но это отвечает на ваш вопрос. Теперь вы можете написать:
double var = toDouble(0xFFFF)
И это вставит данный двоичный шаблон в двойник.

С помощью union писать в один член и читать из другого — неопределенное поведение в C ++, здесь есть отличный вопрос и отличные ответы:
Доступ к неактивному члену объединения и неопределенному поведению?

3
По вопросам рекламы [email protected]