Почему memcpy выдает неожиданное значение?

#include <iostream>
#include <cstring>
#include <bitset>

using namespace std;

int main()
{
    double tx = 0xFFFF0000FFFF0000;
    uint64_t tx1 = 0;
    
    static_assert(sizeof(double) == sizeof(uint64_t));
    memcpy(&tx1, &tx, sizeof(double));
    bitset<64> b1(tx1);
    
    cout << b1 << endl;
    
    return 0;
}

Как я и ожидал, tx1 должен быть 0xFFFF0000FFFF0000.

но b1 дает 0x43EFFFE0001FFFE0.

Я хотел бы знать, как сделать b1 равным 0xFFFF0000FFFF0000.

bitset<64> b1(0xFFFF0000FFFF0000); сделает то, что вы попросите. Боюсь, это на самом деле не отвечает на ваш вопрос, но неясно, почему. Какова цель кода? мне интересно
463035818_is_not_an_ai 26.06.2024 17:51

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

Chukwujiobi Canon 26.06.2024 17:52

Я беру это обратно. C++ поддерживает комплексные числа через стандартную библиотеку. Тем не менее, он использует другое двоичное представление.

Chukwujiobi Canon 26.06.2024 18:19

@ChukwujiobiCanon «однако C++ изначально не поддерживает комплексные числа» - как вы тогда называете std::complex, если не «родной»?

Jesper Juhl 26.06.2024 18:19
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
4
104
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

0xFFFF0000FFFF0000 — это некоторое целочисленное значение, но важно отметить, что double шириной 64 бита может представлять только целые числа до 53 бит. После этого вы просто получите самое близкое приближение.

Когда это произойдет, у вас появится объект double, значение которого близко, но не совсем к 0xFFFF0000FFFF0000.

Затем вы std::memcpy представляете double обратно в целое число, но поскольку двойного числа больше нет 0xFFFF0000FFFF0000, то и ваше целое число не изменится.

Еще следует отметить, что типы с плавающей запятой и целочисленные типы имеют разные двоичные представления. 42 в double не имеет того же двоичного представления, что и 42 в uint64_t. Это значит, что; несмотря ни на что, вы никогда не получите ту же самую битовую комбинацию обратно в результате операции.


Единственное, что вы можете сделать, это использовать memcpy в обоих направлениях.

uint64_t start = 0xFFFF0000FFFF0000;
double tx;
uint64_t tx1;
memcpy(&tx, &start, sizeof(start));
// now `tx` is some value but it has the binary representation of 0xFFFF0000FFFF0000
memcpy(&tx1, &tx, sizeof(tx));
// now tx1 has the binary representation of 0xFFFF0000FFFF0000 since the bits never get changed

Большое спасибо. Могу я спросить еще одну вещь? Не могли бы вы порекомендовать метод копирования двоичного представления double в переменную uint64_t??

Handrix 26.06.2024 17:41

@Handrix У тебя это уже есть. memcpy(&tx1, &tx, sizeof(double)); хранит двоичное представление того, во что было преобразовано целое число 0xFFFF0000FFFF0000, когда оно было сохранено в double. Вот почему я сказал, что оно никогда не будет соответствовать целочисленному представлению. Двоичное представление 42 различается для типов с плавающей запятой и целочисленных типов.

NathanOliver 26.06.2024 17:46

@Handrix, кажется, ты путаешь значение double со значением необработанных байтов. Вы можете посмотреть, например, здесь h-schmidt.net/FloatConverter/IEEE754.html, чтобы увидеть разницу.

463035818_is_not_an_ai 26.06.2024 17:48

Я очень ценю вашу помощь. это очень полезно.

Handrix 26.06.2024 18:05

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