截取字符串的一定的长度在解各种数据包中是非常常用的,怎么实现截取取决于数据包的数据类型。
1、截取两个字节长度:
定义为宏:
#define pntoh16(p) ((uint16_t) \
((uint16_t)*((const uint8_t *)(p)+0)<<8| \
(uint16_t)*((const uint8_t *)(p)+1)<<0))
定义为函数:
uint16_t pntoh16(uint8_t* p)
{
return (uint16_t)|(uint16_t)(p+0)<<8|(uint16_t)(p+1)<<0);
}
2、截取三个字节长度:
定义为宏:
#define pntoh24(p) ((uint32_t)*((const uint8_t *)(p)+0)<<16| \
(uint32_t)*((const uint8_t *)(p)+1)<<8| \
(uint32_t)*((const uint8_t *)(p)+2)<<0)
定义为函数:
uint32_t pntoh24(uint8_t* p)
{
return (uint32_t)((uint32_t)(p)<<16|(uint32_t)(p+1)<<8|(uint32_t)*(p+2)<<0);
}
3、截取四个字节长度:
定义为宏:
#define pntoh32(p) ((uint32_t)*((const uint8_t *)(p)+0)<<24| \
(uint32_t)*((const uint8_t *)(p)+1)<<16| \
(uint32_t)*((const uint8_t *)(p)+2)<<8| \
(uint32_t)*((const uint8_t *)(p)+3)<<0)
定义为函数:
uint32_t pntoh32(uint8_t* p)
{
return (uint32_t)((uint32_t)(p)<<24|(uint32_t)(p+1)<<16|(uint32_t)(p+2)<<8|(uint32_t)(p+3)<<0);
}
以下类似函数省略:
#define pntoh40(p) ((uint64_t)*((const uint8_t *)(p)+0)<<32| \
(uint64_t)*((const uint8_t *)(p)+1)<<24| \
(uint64_t)*((const uint8_t *)(p)+2)<<16| \
(uint64_t)*((const uint8_t *)(p)+3)<<8| \
(uint64_t)*((const uint8_t *)(p)+4)<<0)
#define pntoh48(p) ((uint64_t)*((const uint8_t *)(p)+0)<<40| \
(uint64_t)*((const uint8_t *)(p)+1)<<32| \
(uint64_t)*((const uint8_t *)(p)+2)<<24| \
(uint64_t)*((const uint8_t *)(p)+3)<<16| \
(uint64_t)*((const uint8_t *)(p)+4)<<8| \
(uint64_t)*((const uint8_t *)(p)+5)<<0)
#define pntoh56(p) ((uint64_t)*((const uint8_t *)(p)+0)<<48| \
(uint64_t)*((const uint8_t *)(p)+1)<<40| \
(uint64_t)*((const uint8_t *)(p)+2)<<32| \
(uint64_t)*((const uint8_t *)(p)+3)<<24| \
(uint64_t)*((const uint8_t *)(p)+4)<<16| \
(uint64_t)*((const uint8_t *)(p)+5)<<8| \
(uint64_t)*((const uint8_t *)(p)+6)<<0)
#define pntoh64(p) ((uint64_t)*((const uint8_t *)(p)+0)<<56| \
(uint64_t)*((const uint8_t *)(p)+1)<<48| \
(uint64_t)*((const uint8_t *)(p)+2)<<40| \
(uint64_t)*((const uint8_t *)(p)+3)<<32| \
(uint64_t)*((const uint8_t *)(p)+4)<<24| \
(uint64_t)*((const uint8_t *)(p)+5)<<16| \
(uint64_t)*((const uint8_t *)(p)+6)<<8| \
(uint64_t)*((const uint8_t *)(p)+7)<<0)
有时候我们数据是网络字节序(大端字节序:把值的低位存在高地址)的需要截取并转化成主机字节序(小端字节序:把值得低位存在地地址)。
附加一个判断本机大小端的简单程序
void litterorbig ()
{
unsigned int x = 0x12345678;
char c = (char)&x;
if (*c == 0x78) {
printf(“Little endian”);
} else {
printf(“Big endian”);
}
}
下面分别是截取两、三、四、五、六、七、八字节长度并转换的定义的宏,函数省略:
#define pletoh16(p) ((uint16_t) \
((uint16_t)*((const uint8_t *)(p)+1)<<8| \
(uint16_t)*((const uint8_t *)(p)+0)<<0))
#define pletoh24(p) ((uint32_t)*((const uint8_t *)(p)+2)<<16| \
(uint32_t)*((const uint8_t *)(p)+1)<<8| \
(uint32_t)*((const uint8_t *)(p)+0)<<0)
#define pletoh32(p) ((uint32_t)*((const uint8_t *)(p)+3)<<24| \
(uint32_t)*((const uint8_t *)(p)+2)<<16| \
(uint32_t)*((const uint8_t *)(p)+1)<<8| \
(uint32_t)*((const uint8_t *)(p)+0)<<0)
#define pletoh40(p) ((uint64_t)*((const uint8_t *)(p)+4)<<32| \
(uint64_t)*((const uint8_t *)(p)+3)<<24| \
(uint64_t)*((const uint8_t *)(p)+2)<<16| \
(uint64_t)*((const uint8_t *)(p)+1)<<8| \
(uint64_t)*((const uint8_t *)(p)+0)<<0)
#define pletoh48(p) ((uint64_t)*((const uint8_t *)(p)+5)<<40| \
(uint64_t)*((const uint8_t *)(p)+4)<<32| \
(uint64_t)*((const uint8_t *)(p)+3)<<24| \
(uint64_t)*((const uint8_t *)(p)+2)<<16| \
(uint64_t)*((const uint8_t *)(p)+1)<<8| \
(uint64_t)*((const uint8_t *)(p)+0)<<0)
#define pletoh56(p) ((uint64_t)*((const uint8_t *)(p)+6)<<48| \
(uint64_t)*((const uint8_t *)(p)+5)<<40| \
(uint64_t)*((const uint8_t *)(p)+4)<<32| \
(uint64_t)*((const uint8_t *)(p)+3)<<24| \
(uint64_t)*((const uint8_t *)(p)+2)<<16| \
(uint64_t)*((const uint8_t *)(p)+1)<<8| \
(uint64_t)*((const uint8_t *)(p)+0)<<0)
#define pletoh64(p) ((uint64_t)*((const uint8_t *)(p)+7)<<56| \
(uint64_t)*((const uint8_t *)(p)+6)<<48| \
(uint64_t)*((const uint8_t *)(p)+5)<<40| \
(uint64_t)*((const uint8_t *)(p)+4)<<32| \
(uint64_t)*((const uint8_t *)(p)+3)<<24| \
(uint64_t)*((const uint8_t *)(p)+2)<<16| \
(uint64_t)*((const uint8_t *)(p)+1)<<8| \
(uint64_t)*((const uint8_t *)(p)+0)<<0)
将十六进制转化为字符串
int strtohex(unsigned char *str, int len, char *hexstr)
{
int i, j;
unsigned char c;
static char binhex[16] = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
for(i = 0, j = 0; i < len; i++)
{
c = *str++;
hexstr[j++] = binhex[c>>4];
hexstr[j++] = binhex[c&0xf];
}
hexstr[j]= '\0';
return j;
}
或者
void strtohex(unsigned char*str, int len, char*hexstr)
{
int i;
char cTemp;
for (i = 0; i < len; i++)
{
cTemp = (str[i] & 0xf0) >> 4;
hexstr[i * 2] = (cTemp > 9) ? cTemp + 0x41 - 10 : cTemp + 0x30;
cTemp = str[i] & 0xf;
hexstr[i * 2 + 1] = (cTemp > 9) ? cTemp + 0x41 - 10 : cTemp + 0x30;
}
}
或者
void strtohex(unsigned char *str, int len, char *hexstr)
{
int i, j = 0;
for(i =0 ; i < len; i++)
{
sprintf(hexstr + 2 * i,"%02X", str[i]);
}
}
将字符串转化为十六进制
void hextostr(char*hexstr, int len, unsigned char*str)
{
int i;
char cTemp;
for (i = 0; i < len; i++)
{
cTemp = hexstr[i * 2];
if (cTemp >= 'A' && cTemp <= 'F')
cTemp = cTemp - 'A' + 10;
else if (cTemp >= 'a' && cTemp <= 'f')
cTemp = cTemp - 'a' + 10;
else
cTemp &= 0x0f;
str[i] = cTemp << 4;
cTemp = hexstr[i * 2 + 1];
if (cTemp >= 'A' && cTemp <= 'F')
cTemp = cTemp - 'A' + 10;
else if (cTemp >= 'a' && cTemp <= 'f')
cTemp = cTemp - 'a' + 10;
else
cTemp &= 0x0f;
str[i] += cTemp;
}
return;
}
或者
int hextostr(char *hexstr, int len, unsigned char *str)
{
int i, j = 0;
char temp[2] = {0};
for(i =0 ; i < len; i+=2)
{
memcpy(temp, hexstr + i, 2);
sscanf(temp, "%02X", &str[j]);
j++;
}
return j;
}
注意以上函数没有检查数组的长度,需提前检查长度以防溢出。
如果要截取的长度超过4个字节,用memcpy()函数来实现比较好,如果数据包的是字符串形式的也可以用strcpy(),strncpy(),sprintf(),strlen()等函数实现,建议用memcpy函数
进行各种拷贝。
因最近需要处理IP地址,IP地址在数据包中的形式是32位数字,我们用long int 类型进行存储,点分十进制IP地址用字符串存储,下面是两种形式的转换函数。
长整型转换为字符串
void *long2str(long int num, char *str)
{
sprintf(str, "%u.%u.%u.%u", num >>24 & 0xFF, num >>16 & 0xFF, num >>8 & 0xFF, num >>0 & 0xFF);
}
字符串转换为长整型
long int str2long(char *str)
{
return ntohl(inet_addr(str));
}
说明:inet_addr()和ntohl ()函数需要包含