Я хотел бы присвоить значение переменной, как это:
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
значение интерпретируется только как часть дроби — поэтому ясно, что биты должны использоваться для поля экспоненты и знака. Но кажется, что буквальное просто отрезано.
C ++ не определяет представление в памяти для double
Более того, он даже не определяет представление целочисленных типов в памяти (и может действительно отличаться в системах с разными окончаниями). Так что если вы хотите интерпретировать байты 0xFF
, 0xFF
как double
Вы можете сделать что-то вроде:
uint8_t bytes[sizeof(double)] = {0xFF, 0xFF};
double var;
memcpy(&var, bytes, sizeof(double));
Обратите внимание, что с помощью союзов или reinterpret_cast
Строго говоря, указатели — это неопределенное поведение, хотя на практике это тоже работает.
«Мне было интересно, есть ли способ манипулировать этой интерпретацией».
Да, вы можете использовать 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;
Кажется, не существует прямого способа инициализации 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 ++, здесь есть отличный вопрос и отличные ответы:
Доступ к неактивному члену объединения и неопределенному поведению?