起因
在开发项目中,为了能够读取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;
}
编译截图

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

被折叠的 条评论
为什么被折叠?



