网上很多,socket库里好像也有,但是还是想自己写一个。自我要求有两点,代码要少(要晦涩),支持超网掩码格式。
/*! * @param pcInt * String to parse, don't support negative integer. * * @param iLimit * Only parse a number of chars which is less than iLimit. * The largest choice? Use 10 for int32, 5 for int16. * * @param ppc * returns the pointer where the parser finally reached. * Pass NULL if you don't need this. * * @returns * -1 indicates a failure * otherwise returns the integer parsed. * */ int pc2UnsignedInt(const char* pcInt, int iLimit, const char** ppc) { int iRet = 0; const char* pc = pcInt; while (*pc >= '0' && (*pc - '0') < 10 && iLimit > 0) { --iLimit; iRet = iRet * 10 + (*pc++ - '0'); } iRet = (pc == pcInt) ? -1 : iRet; if (ppc) { *ppc = pc; } return iRet; }
/*! * @param pcIP * String representing an IPv4 address. * pcIP should end with space or nothing. * eg. "192.168.1.101", "192.168.1.101 " and "192.168.1.101 blabla" are all valid. * eg. "192.168.1.101blabla" is not valid. * Forms like "192.168.1.101/24" is also supported. * * @param pi1 * @param pi2 * @param pi3 * @param pi4 * Pass NULL to them if you don't need these values. * * @returns * -1 indicates a failure. * Success when typical IPv4 (eg. "192.168.1.101") : 33 * Success when IPv4 plus netmask code (eg. "192.168.1.101/24") : netmask code (0..32) * */ int IPv4Parser(const char* pcIP, int* pi1, int* pi2, int* pi3, int* pi4) { int iRet = -1, ai[4] = {0}, i = -1; do { ai[++i] = pc2UnsignedInt(pcIP, 3, &pcIP); } while ( ai[i] >= 0 && ai[i] <= 255 && i < 3 && *pcIP++ == '.' ); //} while ( ai[i] >= 0 && ai[i] <= 255 && i < 3 && ( i < 3 ? (*pcIP++ == '.') : TRUE ) ); if (i == 3 && ai[3] >= 0 && ai[3] <= 255) { if (*pcIP == '/') { iRet = pc2UnsignedInt(++pcIP, 2, &pcIP); iRet = (*pcIP == '\0' || *pcIP == ' ') && iRet >= 0 && iRet <=32 ? iRet : -1; } else if (*pcIP == '\0' || *pcIP == ' ') { iRet = 33; } } if (iRet != -1) { if (pi1) { *pi1 = ai[0]; } if (pi2) { *pi2 = ai[1]; } if (pi3) { *pi3 = ai[2]; } if (pi4) { *pi4 = ai[3]; } } return iRet; }
在VS2008下测试过,容错性应该还不错。尚未在纯C的编译器下测试,可能需要修改。
第一个函数也算是个副产品,把字符串转换为整数,功能比crt里面的稍多一些。
调用示例(C++):
int a, b, c, d; int iMaskCode = IPv4Parser("192.168.123.101/23", &a, &b, &c, &d); std::bitset<8> abitsetNetMask[4]; for (int i = 0; i < 4; ++i) { for (int j = 0; j < 8; ++j) { if (iMaskCode > 0) { abitsetNetMask[i].set(7 - j); //Eh, it's weird, to_ulong think bit 0 is at the right side... --iMaskCode; } } } char acNetMask[18] = {0}; sprintf_s<>(acNetMask, "%d.%d.%d.%d", abitsetNetMask[0].to_ulong(), abitsetNetMask[1].to_ulong(), abitsetNetMask[2].to_ulong(), abitsetNetMask[3].to_ulong());
大意就是把192.168.123.101/23解析出来,然后根据/23生成一个子网掩码的字符串。
当然普通的不带超网掩码的字符串也能解析,例如192.168.123.101。
详情参考注释。