我有以下代码,它采用double值并将其转换为十六进制表示,反之亦然。我想知道它是否有任何潜在的问题 - 我是否忽略了一些东西。
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];
是这样的吗?
答案 0 :(得分:2)
是。每次调用sprintf()都会在缓冲区中写入三个字符:两个十六进制数字和一个null来终止字符串。最后一个将在当前实现的缓冲区之外写一个。
答案 1 :(得分:2)
是的,converted
的大小应为bufferSize * 2 + 1
。你需要在字符串末尾留出零或空字符的空间。
sprintf
在字符串的末尾插入一个空字符,但是你没有为它腾出空间;这意味着它正在破坏缓冲区之后的内存中的某些值。很难预测这会产生什么副作用;它可能会破坏其他变量的值,它可能会使程序崩溃,或者它似乎可能正常工作。
答案 2 :(得分:1)
将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
的这种指针类型转换。
我会反过来作为练习:)。
答案 3 :(得分:1)
这是我用来将两个单独的双精度数转换为十六进制(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();
我不是很擅长编写代码,在搜索谷歌搜索结果这个问题之后我没有找到任何解决方案,所以写了这个并且它有效......到目前为止
答案 4 :(得分:0)
是的,字符数组(也称为C字符串)通常应以'\ 0'结尾。这在C中用作长度指示器。
char converted[bufferSize * 2 + 1];
converted[bufferSize*2] = '\0';
or
std::memset(converted, 0, bufferSize*2+1);
答案 5 :(得分:0)
......任何潜在的问题......
hex_to_double2
不检查byte_string
缓冲区中的字符串是否适合:您应该提前检查hexString.size()
,或者为for循环添加退出条件。
您还会返回一个指向本地缓冲区的指针,当hex_to_double2
返回时,该指针超出范围 - 不要这样做。它可能会通过工作来欺骗你......直到它破裂。也许只返回std::vector<unsigned char>
- 这会占用缓冲区生命周期和,您可以使用push_back
修复for循环。
有人
告诉我char converted[bufferSize * 2]
应char converted[bufferSize * 2 + 1]
是的,sprintf
附加一个nul-terminator,因此输出缓冲区应该更大。但是,既然您仍在使用std::string
,那么为什么不将十六进制数字格式化为std::ostringstream
?同样,这将解决您的缓冲区大小问题并为您管理内存。