今天遇到一个奇怪的问题,sprintf_s格式化字符串报错:
看起来像是野指针或数组越界,但仔细阅读代码后,未发现野指针或数组越界。经过排查,发现居然就是sprintf_s造成的。
把出错的代码简化之后,大概就是这样:
unsigned char digitNum[16] = {
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10};
char buf[33];
for (int i = 0; i < 16; i++)
{
sprintf_s(buf + i * 2, 33, "%02x", digitNum[i]);
}
buf[32] = 0;
改正后的代码(注意spintf_s的第2个参数):
unsigned char digitNum[16] = {
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10};
char buf[33];
for (int i = 0; i < 16; i++)
{
sprintf_s(buf + i * 2, 33 - i * 2, "%02x", digitNum[i]);
}
buf[32] = 0;
这段代码的作用就是把一些16进制数转成一个字符串,一开始也没发现代码有什么问题,查阅MSDN,sprintf_s的函数声明:
参考MSDN的例子发现一个问题,sprintf_s的第2个参数填的有问题,既然填充字符的位置向右偏移,那么buffer的剩余容量也应该相应减少。
之所以会导致野指针,估计跟sprintf_s的内部实现有关,可能是访问buffer的时候越界了,导致了莫名其妙的报错。
值得一提的是,简化代码之后,报错变了,这可能和调试器的除错机制有关: