【genius_platform软件平台开发】第三十八讲:记一次用scanf读一个unsigned char的警告

在C++项目中,由于从文件读取IP、子网掩码和网关信息时使用sscanf函数,引发了格式化警告。问题在于尝试将读取的数据写入unsigned char数组,但格式字符串缺少指定数据类型的修饰符。解决方案是在格式字符串中添加'hhu',以正确地匹配unsigned char类型。修改后的代码成功消除了警告,实现了从配置文件中正确解析和存储网络参数。

起因

在开发项目中,为了能够读取ip、mask、getway等信息,使用了从文件中读取数据然后使用sscanf进行格式化,把unsigned char写入到变量中,代码如下:


//////////////////////////////////////////////////////////////////////////
// 获取备份的网络配置信息
 bool CGpIpTools::getBackNetInterfaceInfo(uint32_t* pIp, uint32_t* pNetMask, uint32_t* pGateWay)
{
     LOGMSG("CGpIpTools::getBackNetInterfaceInfo...");

     // 等待耗时统计
     TimePoint nTotalCostTm = currentTime();

     CHECKF(pIp);
     CHECKF(pNetMask);
     CHECKF(pGateWay);

     char szBuff[256] = { 0 };
     unsigned char szTmp[4] = { 0 };

    FILE* pFile = fopen("/etc/network/interfaces_back", "r");
    if (!pFile)
    {
        LOGERROR("CGpIpTools::getBackNetInterfaceInfo fopen is error... filePath=[/etc/network/interfaces_back]");
        return false;
    }

    while (fgets(szBuff, 256, pFile))
    {
    	// 注意此处的用scanf读一个unsigned char
        if (sscanf(szBuff, "address %u.%u.%u.%u", &szTmp[0], &szTmp[1], &szTmp[2], &szTmp[3]) == 4)
        {
            LOGMSG("CGpIpTools::getBackNetInterfaceInfo address [%u.[%u.%u.%u]", szTmp[0], szTmp[1], szTmp[2], szTmp[3]);
            memcpy(pIp, szTmp, 4);
        }
        else if (sscanf(szBuff, "netmask %u.%u.%u.%u", &szTmp[0], &szTmp[1], &szTmp[2], &szTmp[3]) == 4)
        {
            LOGMSG("CGpIpTools::getBackNetInterfaceInfo netmask [%u.[%u.%u.%u]", szTmp[0], szTmp[1], szTmp[2], szTmp[3]);
            memcpy(pNetMask, szTmp, 4);
        }
        else if (sscanf(szBuff, "gateway %u.%u.%u.%u", &szTmp[0], &szTmp[1], &szTmp[2], &szTmp[3]) == 4)
        {
            LOGMSG("CGpIpTools::getBackNetInterfaceInfo gateway [%u.[%u.%u.%u]", szTmp[0], szTmp[1], szTmp[2], szTmp[3]);
            memcpy(pGateWay, szTmp, 4);
        }
        else
        {
            //LOGWARNING("CGpIpTools::getBackNetInterfaceInfo cur record is szBuff=[%s] continue next record...", szBuff);
        }
    }
    fclose(pFile);

    LOGMSG("CGpIpTools::getBackNetInterfaceInfo is suc... nTotalCostTm=[%llu] pIfName=[eth0] pFile=[%s] pIp=[%u] pNetMask=[%u] pGateWay=[%u]", (currentTime() - nTotalCostTm).count(), pFile, *pIp, *pNetMask, *pGateWay);
    return true;
}

执行编译时提示警告信息如下

在这里插入图片描述

解决方案

  • %hhu 指定signed char 或 unsigned char char是1个字节

  • %h 指定short int 或者unsigned short int short 是2个字节

  • C中格式字符串printf()的一般形式为: %[标志][输出最小宽度][.精度][长度]类型, 其中方括号[]中的项为可选项。各项的意义介绍如下:

1.类型:

表示输出类型的格式字符       格式字符意义
a 浮点数、十六进制数字和p-计数法(C99)
A 浮点数、十六进制数字和p-计数法(C99)
c                输出单个字符
d                以十进制形式输出带符号整数(正数不输出符号)
e                以指数形式输出单、双精度实数
E                以指数形式输出单、双精度实数
f                以小数形式输出单、双精度实数
g                以%f%e中较短的输出宽度输出单、双精度实数,%e格式在指数小于-4或者大 于等于精度时使用
G                以%f%e中较短的输出宽度输出单、双精度实数,%e格式在指数小于-4或者大于等于精度时使用
i 有符号十进制整数(与%d相同)
o                以八进制形式输出无符号整数(不输出前缀O)
p 指针
s                 输出字符串
x                 以十六进制形式输出无符号整数(不输出前缀OX)
X               以十六进制形式输出无符号整数(不输出前缀OX)
u                 以十进制形式输出无符号整数

2.标志

  • 标志字符为-、+、#、空格和0五种,其意义下表所示:/:为了转移格式

标志格式字符       标 志 意 义
/-           结果左对齐,右边填空格
/+           输出符号(正号或负号)
/空格 输出值为正时冠以空格,为负时冠以负号
/# 对c,s,d,u类无影响;对o类,在输出时加前缀0;对x类, 在输出时加前缀0x或者0X;对g,G 类防止尾随0被删除;对于所有的浮点形式,#保证了即使不跟任何数字,也打印一个小数点字符
0 对于所有的数字格式,用前导0填充字段宽度,若出现-标志或者指定了精度(对于整数),忽略

3.输出最小宽度

  • 用十进制整数来表示输出的最少位数。若实际位数多于定义的宽度,则按实际位数输出,若实际位数少于定义的宽度则补以空格或0。

4.精度

  • 精度格式符以“.”开头,后跟十进制整数。本项的意义是:如果输出数字,则表示小数的位数;如果输出的是字符,则表示输出字符的个数;若实际位数大于所定义的精度数,则截去超过的部分。

5.长度

  • 长度格式符为h,l两种,h表示按短整型量输出,l表示按长整型量输出。
    h和整数转换说明符一起使用,表示一个short int 或者unsigned short int类型的数值 ,示例:
    %hu,%hx,%6.4hd
    hh和整数转换说明符一起使用,表示一个short int 或者unsigned short类型的数值 ,示例:
    %hhu,%hhx,%6.4hhd
    j和整数转换说明符一起使用,表示一个intmax_t或者uintmax_t类型的数值 ,示例:
    %jd,%8jx
    l和整数转换说明符一起使用,表示一个long int 或者unsigned long int类型的数值 ,示例:
    %ld,%8lu
    ll和整数转换说明符一起使用,表示一个long int 或者unsigned long int类型的数值 (C99),示例:
    %lld,%8llu
    L和浮点转换说明符一起使用,表示一个long double的值,示例:%Lf,%10.4Le
    t和整数转换说明符一起使用,表示一个ptrdiff_t值(两个指针之间的差相对应的类型)(C99),示例:
    %td,%12ti
    z和整数转换说明符一起使用,表示一个size_t值(sizeof返回的类型)(C99),示例:%zd,%12zx

  • 使用printf函数时还要注意一个问题,那就是输出表列中的求值顺序。不同的编译系统不一定相同,可以从左到右,也可从右到左。Turbo C是按从右到左进行的。

修改后源码


//////////////////////////////////////////////////////////////////////////
// 获取备份的网络配置信息
 bool CGpIpTools::getBackNetInterfaceInfo(uint32_t* pIp, uint32_t* pNetMask, uint32_t* pGateWay)
{
     LOGMSG("CGpIpTools::getBackNetInterfaceInfo...");

     // 等待耗时统计
     TimePoint nTotalCostTm = currentTime();

     CHECKF(pIp);
     CHECKF(pNetMask);
     CHECKF(pGateWay);

     char szBuff[256] = { 0 };
     unsigned char szTmp[4] = { 0 };

    FILE* pFile = fopen("/etc/network/interfaces_back", "r");
    if (!pFile)
    {
        LOGERROR("CGpIpTools::getBackNetInterfaceInfo fopen is error... filePath=[/etc/network/interfaces_back]");
        return false;
    }

    while (fgets(szBuff, 256, pFile))
    {
    	// 修改处
        if (sscanf(szBuff, "address %hhu.%hhu.%hhu.%hhu", &szTmp[0], &szTmp[1], &szTmp[2], &szTmp[3]) == 4)
        {
            LOGMSG("CGpIpTools::getBackNetInterfaceInfo address [%hhu.%hhu.%hhu.%hhu]", szTmp[0], szTmp[1], szTmp[2], szTmp[3]);
            memcpy(pIp, szTmp, 4);
        }
        else if (sscanf(szBuff, "netmask %hhu.%hhu.%hhu.%hhu", &szTmp[0], &szTmp[1], &szTmp[2], &szTmp[3]) == 4)
        {
            LOGMSG("CGpIpTools::getBackNetInterfaceInfo netmask [%hhu.%hhu.%hhu.%hhu]", szTmp[0], szTmp[1], szTmp[2], szTmp[3]);
            memcpy(pNetMask, szTmp, 4);
        }
        else if (sscanf(szBuff, "gateway %hhu.%hhu.%hhu.%hhu", &szTmp[0], &szTmp[1], &szTmp[2], &szTmp[3]) == 4)
        {
            LOGMSG("CGpIpTools::getBackNetInterfaceInfo gateway [%hhu.%hhu.%hhu.%hhu]", szTmp[0], szTmp[1], szTmp[2], szTmp[3]);
            memcpy(pGateWay, szTmp, 4);
        }
        else
        {
            //LOGWARNING("CGpIpTools::getBackNetInterfaceInfo cur record is szBuff=[%s] continue next record...", szBuff);
        }
    }
    fclose(pFile);

    LOGMSG("CGpIpTools::getBackNetInterfaceInfo is suc... nTotalCostTm=[%llu] pIfName=[eth0] pFile=[%s] pIp=[%u] pNetMask=[%u] pGateWay=[%u]", (currentTime() - nTotalCostTm).count(), pFile, *pIp, *pNetMask, *pGateWay);
    return true;
}
 

编译截图

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

隨意的風

如果你觉得有帮助,期待你的打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值