C ++将二进制数据转换为十六进制字符串并返回

时间:2011-09-09 15:12:37

标签: c++ visual-studio string binary

我在实用程序类中有一对匹配的静态函数,用于在二进制数据(无符号字符)和它的字符串表示(a-f和0-9)之间进行转换。它们似乎工作正常,但最近我尝试在Visual C ++(2010 Express)下编译我的代码,令我沮丧的是,它们只会导致堆损坏错误。我做错了什么?

void Utility::string_to_binary(const std::string source, unsigned char* destination, unsigned int length)
{
    unsigned int effective_length = min(length, (unsigned int) source.length() / 2);
    for(unsigned int b = 0; b < effective_length; b++)
    {
        sscanf(source.data() + (b * 2), "%02x", (unsigned int*) &destination[b]);
    }
}

void Utility::binary_to_string(const unsigned char* source, unsigned int length, std::string& destination)
{
    destination.clear();
    for(unsigned int i = 0; i < length; i++)
    {
        char digit[3];
        sprintf(digit, "%02x", source[i]);
        destination.append(digit);
    }
}

编辑:这是一个说明问题的完整程序。

#include <iostream>
#include <hdcs/Utility.h>

using namespace std;

int main(int argc, char* argv[])
{
    //Generate some data
    unsigned int size = 1024;
    unsigned char* data = new unsigned char[size];

    //Convert it to it's string representation
    string hex;
    Utility::binary_to_string(data, size, hex);

    //Output it to the screen
    cout << hex << endl;

    //Clear the data buffer
    memset(data, 0, sizeof(unsigned char) * size);

    //Convert the hex string back to binary
    Utility::string_to_binary(hex, data, size);

    //Cleanup
    delete[] data;
}

错误发生在delete[] data

3 个答案:

答案 0 :(得分:3)

您的sscanf会将unsigned int写入您提供的内存位置。通常,unsigned int的长度为4或8个字节,而您只打算提供1个字节。所以最后你在动态数组的末尾运行平稳。

顺便说一下,你的代码与现代的,惯用的C ++相去甚远 - 它本质上只是一个美化的C混乱。我强烈建议用C ++的精神重写它。

答案 1 :(得分:2)

在此代码中,

for(unsigned int b = 0; b < effective_length; b++)
{
    sscanf(source.data() + (b * 2), "%02x", (unsigned int*) &destination[b]);
}

您似乎在地点unsigned intdestinationdestination+1和&amp; c处写了destination+2。当您接近destination缓冲区的最后字节时,您将超出其限制。

为了举例,我们假设目标是一个四字节缓冲区,并且sizeof (unsigned int)在您的环境中是4。然后每个sscanf写入四个字节。

第一次迭代写入字节0,1,2,3

第二个iteratino写入字节1,2,3,4

第三次迭代写入字节2,3,4,5

最后一次迭代写入字节3,4,5,6

由于缓冲区只有四个字节,因此您已经写入了缓冲区的末尾。吊杆。

<小时/> 的修改

避免此特定错误所需的最小更改如下:

for(unsigned int b = 0; b < effective_length; b++)
{
    unsigned int ui;
    sscanf(source.data() + (b * 2), "%02x", &ui);
    destination[b] = ui;
}

答案 2 :(得分:2)

我会重写代码以实际使用C ++工具(没有真正测试过,只是一个想法):

std::vector<unsigned char> string_to_binary(const std::string& source)
{
    static int nibbles[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 14, 15 };
    std::vector<unsigned char> retval;
    for (std::string::const_iterator it = source.begin(); it < source.end(); it += 2) {
        unsigned char v = 0;
        if (std::isxdigit(*it))
            v = nibbles[std::toupper(*it) - '0'] << 4;
        if (it + 1 < source.end() && std::isxdigit(*(it + 1)))
            v += nibbles[std::toupper(*(it + 1)) - '0'];
        retval.push_back(v);
    }
    return retval;
}

std::string binary_to_string(const std::vector<unsigned char>& source)
{
    static char syms[] = "0123456789ABCDEF";
    std::stringstream ss;
    for (std::vector<unsigned char>::const_iterator it = source.begin(); it != source.end(); it++)
        ss << syms[((*it >> 4) & 0xf)] << syms[*it & 0xf];

    return ss.str();
}