sscanf 的一个坑

在一次项目中,偶然使用了sscanf,这里就不详细说明它的用法,开门见山,说一下本文的意图,也希望其他同族兄弟了解。

上程序代码:

struct xxx{
        unsigned char a[6];
        char    b[16];
};
int main(int argc, char** argv)
{
        struct xxx  xyz;
        memset(&xyz, 0, sizeof(struct xxx));
        strcpy(xyz.b, argv[1]);
        sscanf(argv[2], "%x:%x:%x:%x:%x:%x", &(xyz.a[0]), &(xyz.a[1]), &(xyz.a[2]), &(xyz.a[3]), &(xyz.a[4]), &(xyz.a[5]));
        printf("%s\n", xyz.b);
        return 0;
}

执行:./test  enp2s0  12:23:34:45:45:56

打印结果:xyz.b输出为空

gcc  -g  test.c  -o  test

上GDB调试结果:

说明一下,第一步,初始化xyz变量内存为0;

第二步,通过strcpy,将xyz.b赋值,图中显示为16进制;

第三部,执行sscanf后,xyz.a的数值诸葛元素赋值,但是xyz.b的前三个字节被置0了。

最终导致xyz.b输出为空。

原因说明:一定要摒弃老祖宗流传下来的玄学,开发过程中遇到的问题一定是有原因的。这里的问题显然是在执行sscanf之后出现了,那就只能深入看一下sscanf的使用。

sscanf 类型说明符:

类型

合格的输入

参数的类型

c

单个字符:读取下一个字符。如果指定了一个不为 1 的宽度 width,函数会读取 width 个字符,并通过参数传递,把它们存储在数组中连续位置。在末尾不会追加空字符。

char *

d

十进制整数:数字前面的 + 或 - 号是可选的。

int *

e,E,f,g,G

浮点数:包含了一个小数点、一个可选的前置符号 + 或 -、一个可选的后置字符 e 或 E,以及一个十进制数字。两个有效的实例 -732.103 和 7.12e4

float *

o

八进制整数。

int *

s

字符串。这将读取连续字符,直到遇到一个空格字符(空格字符可以是空白、换行和制表符)。

char *

u

无符号的十进制整数。

unsigned int *

x,X

十六进制整数。

int *

sscanf(argv[2], "%x:%x:%x:%x:%x:%x", &(xyz.a[0]), &(xyz.a[1]), &(xyz.a[2]), &(xyz.a[3]), &(xyz.a[4]), &(xyz.a[5]));

程序中使用了%x,对应输入参数类型应该是int*,说明参数的原类型应该是4bytes,而这里xyz.a 数组中每个元素是一个字节,当做内存拷贝时,xyz.a[5] 实际被复制的按16进制表示是0x00000067。x86_64平台的内存存储是小端字节序(高字节在高位,低字节在低位),而这里GDB展示的是从低字节到高字节,从左往右,所以这里 xyz的头三个字节被3个0x00覆盖了。

因此只能将程序中的字符串mac地址转化成 int ,scanf输入参数的原型就不支持unsigned char。其实,单从这个程序而言,可以调换xyz.a 和 xyz.b的赋值顺序,也可以实现,下面来看一下:

但是切记,实际项目中慎用这种方式转化mac地址,要不然你一定会付出代价!!

 

 

 

猜你喜欢

转载自blog.csdn.net/qq_24436765/article/details/107361854
今日推荐