从一个CString字符串解析IP地址和掩码的代码,VS2022工程,全工程为Unicode宽字符配置,所以用了vs的宽窄兼容宏。代码如下:
- unsigned int auiIpAddr[4] = {0};
- TCHAR atMask[100] = {0};
-
- CString tmp = _T("ip address 202.103.97.4 24"); //即解析命令ip address IP地址 掩码
- _stscanf_s(tmp, _T("ip address %u.%u.%u.%u %s"),
- &auiIpAddr[0], &auiIpAddr[1], &auiIpAddr[2], &auiIpAddr[3],
- atMask, sizeof(atMask));
结果发现auiIpAddr里的每个元素都是0xFE,atMask倒是对的,扫到了24。
_stscanf_s是个宽窄兼容的宏函数,对应到这里的宽字符版本,编译时自动被换成了swscanf_s函数。该函数是swscanf的安全版本,扫描字符串时要求加上长度,以免溢出,具体使用请参见MSDN。
查了半下午,发现问题就出在这个缓冲区长度。这里TCHAR数组atMask是100个元素的,在_stscanf_s里需要写成100,不能用sizeof。由于是宽字符版本,所以sizeof(atMask)出来是100 * 2 = 200,而_stscanf_s要求的缓冲区长度是数组的元素个数,不是字节数,所以出错了。
因为_stscanf_s是宽窄兼容版本,所以用户无需指定字符串缓冲区的字节数,函数会根据宽版本or窄版本自己计算字,给出字符个数才符合兼容的设计原则。
因此上述代码改成:
- _stscanf_s(tmp, _T("ip address %u.%u.%u.%u %s"),
- &auiIpAddr[0], &auiIpAddr[1], &auiIpAddr[2], &auiIpAddr[3],
- atMask, 17);
即可。