使用RtlIpv4StringToAddressA和RtlIpv6StringToAddressA校验IP地址合法性时的数据类型转换问题
调试时IPv4地址判断返回FALSE,"Error reading characters of String"问题修复
你的问题核心在于Unicode环境下的字符串类型强制转换错误,导致RtlIpv4StringToAddressA拿到了错误的字符串数据,进而解析失败。
问题根源分析
在MFC默认的Unicode配置中,CString本质是CStringW(宽字符类型,每个字符占2字节)。你代码里的强制转换:
PCSTR ip = ((PCSTR)(PCTSTR)strIPAddr);
只是把const wchar_t*(PCTSTR在Unicode下的定义)强转成了const char*,但内存里的字符串还是宽字节格式。比如输入127.0.0.1,内存里的内容是'1','\0','2','\0','7','\0',...,RtlIpv4StringToAddressA作为ANSI版本函数,会把第一个\0当作字符串结束符,自然无法解析完整的IPv4地址,同时调试器读取这个错误的指针时,就会抛出"Error reading characters of String"提示。
两种修复方案
方案1:使用Unicode版本的Rtl函数(推荐)
既然MFC默认用宽字符,直接调用RtlIpv4StringToAddressW和RtlIpv6StringToAddressW,不需要做类型转换,代码更安全:
static BOOL checkIp(CString strIPAddr) { BOOL result(FALSE); PCWSTR ip = strIPAddr; // Unicode下CString可直接转PCWSTR,无需强制转换 PCWSTR Terminator; in_addr aIpv4; in6_addr aIpv6; if (RtlIpv4StringToAddressW(ip, TRUE, &Terminator, &aIpv4) == STATUS_SUCCESS) { result = TRUE; } else if (RtlIpv6StringToAddressW(ip, &Terminator, &aIpv6) == STATUS_SUCCESS) { result = TRUE; } return result; }
方案2:将CString转换为ANSI字符串
如果一定要用ANSI版本的函数,需要先把宽字符的CString转换成ANSI编码的CStringA,再传递给函数:
static BOOL checkIp(CString strIPAddr) { BOOL result(FALSE); CStringA strIPAddrA(strIPAddr); // 宽字符转ANSI字符串 PCSTR ip = strIPAddrA; PCSTR Terminator; in_addr aIpv4; in6_addr aIpv6; if (RtlIpv4StringToAddressA(ip, TRUE, &Terminator, &aIpv4) == STATUS_SUCCESS) { result = TRUE; } else if (RtlIpv6StringToAddressA(ip, &Terminator, &aIpv6) == STATUS_SUCCESS) { result = TRUE; } return result; }
额外提示
RtlIpv4StringToAddress的第二个参数Strict设为TRUE时,会严格校验IPv4格式(比如不允许前导零,除非是单个0)。如果你的场景需要兼容宽松格式的IPv4地址,可以把这个参数改成FALSE。
内容的提问来源于stack exchange,提问作者kubenzi
相关产品推荐
相关产品推荐

