Преобразование двойного в шестнадцатеричное - обзор кода - PullRequest
2 голосов
/ 03 апреля 2012

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

double hex_to_double2(string &hexString)
{
    unsigned char byte_string[sizeof(double)];
    int number;

    int j = 0;

    for(int i = 0; i < hexString.size() ; i += 2)
    {
        sscanf(&hexString[i], "%02x", &number);
        byte_string[j] = (unsigned char)number;
        ++j;
    }

    double p = (double&)byte_string;
    return p;
}

std::string double_to_hex_string(double d)
{
    unsigned char *buffer = (unsigned char*)&d;
    int bufferSize = sizeof(double);

    char converted[bufferSize * 2];

    int j = 0;
    for(int i = 0 ; i < bufferSize ; ++i)
    {
        sprintf(&converted[j*2], "%02X", buffer[i]);
        ++j;
    }
    string hex_string(converted);
    return hex_string;
}

Кажется, это работает нормально.Но кто-то сказал мне, что char converted[bufferSize * 2]; должно быть char converted[bufferSize * 2 + 1];

Так ли это?

Ответы [ 6 ]

2 голосов
/ 03 апреля 2012

Да, размер converted должен быть bufferSize * 2 + 1. Вам нужно место для нулевого или нулевого символа в конце строки.

sprintf вставляет нулевой символ в конец строки, но вы не освободили место для него; это означает, что он уничтожает некоторое значение в памяти, которое приходит сразу после буфера. Трудно предсказать, какой побочный эффект это может иметь; он может испортить значение какой-либо другой переменной, может вызвать сбой вашей программы или может показаться, что он работает нормально.

2 голосов
/ 03 апреля 2012

Да. Каждый вызов sprintf () будет записывать в ваш буфер три символа: две шестнадцатеричные цифры и ноль для завершения строки. Последний из них запишет один за пределы буфера, как в настоящее время реализовано.

1 голос
/ 11 октября 2012

Это очень простой метод, который я использую для преобразования двух отдельных чисел с максимальным значением 255 в шестнадцатеричное (firstNumber и secondNumber):

std::string hexCodes = "0123456789abcdef";

std::stringstream finalResult;

finalResult << hexCodes.at(floor(firstNumber/ 16)) << hexCodes.at(firstNumber- (16 * (floor(firstNumber/ 16))));

finalResult << hexCodes.at(floor(secondNumber/ 16)) << hexCodes.at(secondNumber- (16 * (floor(secondNumber/ 16))));

std::string finalString = finalResult.str();

Я не очень хорош в написании кода и послетраля гугл за результат к этой проблеме я не нашел никаких решений, поэтому написал это и все работает ... пока что

1 голос
/ 03 апреля 2012

Еще одна проблема с положением double в char byte_string [sizeof(double)] - это выравнивание . Эта довольно хитрая стратегия называется type punning . Вам также нужно выделить sizeof(double)*2 байтов в этой функции, а затем создать выровненный указатель в середине буфера.

Как правило, подобного рода "разбрасывание" является плохой идеей, но вы почти правы. Вы просто хотите привести double к массиву char, а не наоборот. Кроме того, scanf может сделать больше за вас и исключить петлю.

double hex_to_double2(string &hexString)
{
    double value;

    sscanf( hexString.c_str(), "%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx",
            (char*) & value, // note, this is a reinterpret_cast
            (char*) & value + 1,
            (char*) & value + 2,
            (char*) & value + 3,
            (char*) & value + 4,
            (char*) & value + 5,
            (char*) & value + 6,
            (char*) & value + 7 );

    return p;
}

Вам разрешено использовать указатель типа такого типа только от типов POD (простые старые данные или C-совместимые) до char.

Я оставлю наоборот как упражнение :).

0 голосов
/ 03 апреля 2012

... любые потенциальные проблемы ...

hex_to_double2 не проверяет соответствие строк в буфере byte_string: вам следует либо заранее проверить hexString.size()или добавьте условие выхода в цикл for.

Вы также возвращаете указатель на локальный буфер, который выходит из области видимости при возврате hex_to_double2 - не делайте этого.Он может обмануть вас, работая ... пока не сломается.Может быть, просто верните std::vector<unsigned char> - это позаботится о времени жизни буфера и , вы можете исправить цикл for, используя push_back.

Мне кто-то сказал, чтоchar converted[bufferSize * 2] должно быть char converted[bufferSize * 2 + 1]

Да, sprintf добавляет нуль-терминатор, поэтому ваш выходной буфер должен быть больше.Но, так как вы все равно используете std::string, почему бы просто не отформатировать шестнадцатеричные цифры в std::ostringstream?Опять же, это позволит исправить проблемы с размером буфера и управлять памятью.

0 голосов
/ 03 апреля 2012

Да, символьные массивы (также известные как строки C) обычно должны заканчиваться символом '\ 0'. Это работает как индикатор длины в C.

char converted[bufferSize * 2 + 1];
converted[bufferSize*2] = '\0';
or
std::memset(converted, 0, bufferSize*2+1);
...