使用 sscanf 时的问题
Issue when using sscanf
我正在尝试用 C 编写一个脚本,它从文件 /proc/net/dev
中读取带宽信息并对其进行处理以产生每秒上传和下载流量。
文件如下所示:
Inter-| Receive | Transmit
face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
lo: 4845 60 0 0 0 0 0 0 4845 60 0 0 0 0 0 0
enp3s0: 197557966 217836 0 0 0 0 0 591 21516707 160167 0 0 0 0 0 0
sit0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
我在两个网络之间切换(另一个网络当前未在文件中列出)所以我将网络设备的名称作为参数。
目前 enp3s0
是我从中获取网络信息的设备。
现在我遇到的问题是当我尝试使用 sscanf
处理所需的行时。
出于某种原因,sscanf 总是为我从中读取的各种值生成乱码输出。
所以我制作了一个单独的测试文件,我在其中直接将行声明为字符串并使用几乎完全相同的逻辑,其中它按预期完美运行。
主文件:
注意:某些行在故障排除期间被注释掉了。
有些行仅用于详细输出。
还有字节转换的部分还留着,因为我遇到这个问题就没有再进一步了。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#define NETWORK_FILE "/proc/net/dev"
//==========================FUNC_DECL
unsigned long * receive(FILE *,char*);
char *searchstr(FILE *,char *);
//===========================TYPE-STRING
typedef char *String;
//===========================FUNCTIONS
// The function that looks for argv[1] in the NETWORK_FILE and returns the line as char *.
char *searchstr(FILE *ndev,char *netid){
int found=0,lineno=1;
char tmpf[600];
//GETTING THE LINE MATCH
while(fgets(tmpf,sizeof(tmpf),ndev) != NULL){
if(strstr(tmpf,netid) != NULL) {
printf("Device %s Found on Line %d",netid,lineno);
found++;
break;
}
lineno++;
}
if (found==0){ printf("ERROR!::NO_NET_DEVICE::No such device exists as %s\n",netid); }
char *line = tmpf;
if(line == NULL){ printf("ERROR!:SEARCHSTR_NULL_LINE_RET: Empty Line being sent for parsing"); exit(2);}
return line;
}
//The function that sends Upload and Download bytes to the Main function in an array ptr form.. sort of
unsigned long * receive(FILE *dev,char *netname) {
unsigned int dspeed=0,uspeed=0,dump;
unsigned long rcv1,rcv2,trv1,trv2;
char *n_line = (char *)malloc(200*sizeof(char));
char *drop =(char *) malloc(15*sizeof(char));
n_line = searchstr(dev,netname);
if(n_line == NULL){ printf("Error!: No Line received for parsing"); }
printf("\n Line Input is: \n%s",n_line);
//--------THIS IS THE MAIN LINE WHERE THE PROBLEM IS. THE LINE BELOW IT IS THE ONE I WROTE TO TROUBLESHOOT
/*sscanf(n_line,"%s %lu %u %u %u %u %u %u %u %lu %u %u %u %u %u %u %u",drop,&rcv1,&dump,&dump,&dump,&dump,&dump,&dump,&dump,&trv1,&dump,&dump,&dump,&dump,&dump,&dump,&dump);*/
sscanf(n_line,"%s%lu",drop,&rcv1);
printf("\nDrop is read as: \t %s\nRx is %lu",drop,rcv1);
if(rcv1 == 0){ printf("\nError!:NULL_VALUE-RX-1: Value received for parsing is 0."); }
sleep(1);
sscanf(n_line,"%s %lu %u %u %u %u %u %u %u %lu %u %u %u %u %u %u %u", drop,&rcv2,&dump,&dump,&dump,&dump,&dump,&dump,&dump,&trv2,&dump,&dump,&dump,&dump,&dump,&dump,&dump);
if(rcv2 == 0){ printf("Error!:NULL_VALUE-RX-2: Value received for parsing is 0."); }
dspeed = rcv2-rcv1;
uspeed = trv2-trv1;
unsigned long *speeds [2];
speeds[0] = &dspeed;
speeds[1] = &uspeed;
return *speeds;
}
//==========================Main
int main(int argc,char *argv[]) {
FILE *netdev;
String networkid = malloc(10);
networkid=argv[1];
netdev = fopen(NETWORK_FILE,"r");
if (netdev == NULL) { printf("Error Opening file!"); return (-1); }
unsigned long *spd[2];
*spd = receive(netdev,networkid);
printf("\n D: %lu | U: %lu \n",*spd[0],*spd[1]);
fclose(netdev);
}
测试文件:
注意:测试文件的值稍旧,因为它使用旧的复制粘贴。
#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
char *w1,*w2,*w3,*w4,*w5;
w1 = (char*) malloc(8*sizeof(char));
w2 = (char*) malloc(8*sizeof(char));
w3 = (char*) malloc(8*sizeof(char));
w4 = (char*) malloc(8*sizeof(char));
w5 = (char*) malloc(15*sizeof(char));
unsigned long n1,n2,d1,d2,d3,d4,d5,d6,d7;
char *teststring,*devstring;
devstring = (char *) malloc(150*sizeof(char));
devstring = "enp3s0: 168010376 192508 0 0 0 0 0 547 19528703 142230 0 0 0 0 0 0";
sscanf(devstring,"%s %lu",w5,&d1);
printf("\n\nDev line parse is:\n %s RX: %lu\n",w5,d1);
}
输出
主文件
Device enp3s0 Found on Line 4
Line Input is:
enp3s0: 197678794 218123 0 0 0 0 0 617 21694353 160864 0 0 0 0 0 0
Drop is read as: <= There is usually gibberish here. Its different everytime. And sometimes its not there at all
Rx is 94544931811891
D: 94544931811891
测试文件
Dev line parse is:
enp3s0: RX: 168010376
我几乎是 C 语言的初学者(这是我第一个使用指针的程序。我仍然无法理解这些)所以肯定会以 worst/dumb 可以想象的方式完成一些事情.欢迎指正。
编辑:
所以根据@Mathieu 的回答,我尝试合并一个 return 检查 sscanf:
int assign_count = sscanf(n_line,"%s %lu %*u %*u %*u %*u %*u %*u %*u %lu %*u %*u %*u %*u %*u %*u %*u",drop,&rcv1,&trv1);
if(assign_count == 3){
printf("\nRx is %lu",rcv1);
}else { printf("\nERROR!::RECEIVE_ASSIGN_FAILURE:: Failed to assign %d values(Current: %d)",3,assign_count); }
输出:
这随机给了我两个不同的输出。
Device enp3s0 Found on Line 4
Line Input is:
enp3s0: 201330925 226694 0 0 0 0 0 790 23566091 172240 0 0 0 0 0 0
ERROR!::RECEIVE_ASSIGN_FAILURE:: Failed to assign 3 values(Current: -1)
D: 93951710999123
Device enp3s0 Found on Line 4
Line Input is:
enp3s0: 201339561 226756 0 0 0 0 0 798 23586994 172381 0 0 0 0 0 0
ERROR!::RECEIVE_ASSIGN_FAILURE:: Failed to assign 3 values(Current: 2)
Error!:NULL_VALUE-RX-1: Value received for parsing is 0.Error!:NULL_VALUE-RX-2: Value received for parsing is 0.
D: 0
在一种情况下,ret
或 assign_count
显示为 -1,在另一种情况下显示为 2。此外,在某些执行中,我遇到了 Segmentation Fault也是随机的。
您对 sscanf
的使用可能会更好:
- 在使用其结果
之前先阅读sscanf
的结果
- 知道 scanf 会忽略要读取的字段之间的额外 space,您可以在
format
参数中只写一个
- 要求
sscanf
使用 %*..
忽略某些字段
因此,您的代码将变为:
#include <stdio.h>
int main(void) {
char *lines[] = {
" lo: 4845 60 0 0 0 0 0 0 4845 60 0 0 0 0 0 0",
"enp3s0: 197557966 217836 0 0 0 0 0 591 21516707 160167 0 0 0 0 0 0",
" sit0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"
};
long unsigned int rcv2, trv2, i;
char name[256];
for (i = 0; i < 3; ++i)
{
int ret = sscanf(lines[i],"%s %lu %*u %*u %*u %*u %*u %*u %*u %lu %*u %*u %*u %*u %*u %*u %*u", name,&rcv2,&trv2);
if (3 == ret)
printf("%s, %lu, %lu\n", name, rcv2, trv2);
else
printf("Error: %d conversion(s) instead of 3\n", ret);
}
}
好的,在进一步的故障排除后,我发现 n_line
已损坏。它作为一个整体打印正确,但当我尝试解析它时,它有一些问题。
首先,我通过使用 strtok
和 for
循环打印拆分字符串来分析 searchstr
函数中的 tmpf
变量。 - 它按预期正确打印
char *wd;
wd = strtok(tmpf," ");
while( wd != NULL){
printf("::%s\n",wd);
wd = strtok(NULL," ");
}
但是当我在 n_line
上的 receive
函数中 运行 相同时,它会产生损坏的输出 - 要么打印第一个字符串,要么从该行随机打印一些数字.
解决方案:..有点
然而,当我将 tmpf
声明为 static
.
时,整个问题突然消失了
当声明为 static
时,sscanf
正确写入所有变量并且详细输出也正确。
Device enp3s0 Found on Line 4
tmpf is : enp3s0: 4054772 8380 0 0 0 0 0 131 1842262 11148 0 0 0 0 0 0
Line Input is:
enp3s0: 4054772 8380 0 0 0 0 0 131 1842262 11148 0 0 0 0 0 0
Rx is 4054772 | Tx is 1842262
我真的不知道为什么它会突然工作,但我的猜测是 static
使 tmpf
在两个函数中都保留在内存中,因此我能够在第二个功能。仍然感觉这更像是 hack 而不是实际的解决方案。
其他一些输出也被破坏,但这可能不是这个问题的一部分。
编辑:
我刚刚还找到了一个消息来源,说明了这一点:
https://www.tutorialspoint.com/cprogramming/c_return_arrays_from_function.htm
我正在尝试用 C 编写一个脚本,它从文件 /proc/net/dev
中读取带宽信息并对其进行处理以产生每秒上传和下载流量。
文件如下所示:
Inter-| Receive | Transmit
face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
lo: 4845 60 0 0 0 0 0 0 4845 60 0 0 0 0 0 0
enp3s0: 197557966 217836 0 0 0 0 0 591 21516707 160167 0 0 0 0 0 0
sit0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
我在两个网络之间切换(另一个网络当前未在文件中列出)所以我将网络设备的名称作为参数。
目前 enp3s0
是我从中获取网络信息的设备。
现在我遇到的问题是当我尝试使用 sscanf
处理所需的行时。
出于某种原因,sscanf 总是为我从中读取的各种值生成乱码输出。
所以我制作了一个单独的测试文件,我在其中直接将行声明为字符串并使用几乎完全相同的逻辑,其中它按预期完美运行。
主文件:
注意:某些行在故障排除期间被注释掉了。 有些行仅用于详细输出。 还有字节转换的部分还留着,因为我遇到这个问题就没有再进一步了。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#define NETWORK_FILE "/proc/net/dev"
//==========================FUNC_DECL
unsigned long * receive(FILE *,char*);
char *searchstr(FILE *,char *);
//===========================TYPE-STRING
typedef char *String;
//===========================FUNCTIONS
// The function that looks for argv[1] in the NETWORK_FILE and returns the line as char *.
char *searchstr(FILE *ndev,char *netid){
int found=0,lineno=1;
char tmpf[600];
//GETTING THE LINE MATCH
while(fgets(tmpf,sizeof(tmpf),ndev) != NULL){
if(strstr(tmpf,netid) != NULL) {
printf("Device %s Found on Line %d",netid,lineno);
found++;
break;
}
lineno++;
}
if (found==0){ printf("ERROR!::NO_NET_DEVICE::No such device exists as %s\n",netid); }
char *line = tmpf;
if(line == NULL){ printf("ERROR!:SEARCHSTR_NULL_LINE_RET: Empty Line being sent for parsing"); exit(2);}
return line;
}
//The function that sends Upload and Download bytes to the Main function in an array ptr form.. sort of
unsigned long * receive(FILE *dev,char *netname) {
unsigned int dspeed=0,uspeed=0,dump;
unsigned long rcv1,rcv2,trv1,trv2;
char *n_line = (char *)malloc(200*sizeof(char));
char *drop =(char *) malloc(15*sizeof(char));
n_line = searchstr(dev,netname);
if(n_line == NULL){ printf("Error!: No Line received for parsing"); }
printf("\n Line Input is: \n%s",n_line);
//--------THIS IS THE MAIN LINE WHERE THE PROBLEM IS. THE LINE BELOW IT IS THE ONE I WROTE TO TROUBLESHOOT
/*sscanf(n_line,"%s %lu %u %u %u %u %u %u %u %lu %u %u %u %u %u %u %u",drop,&rcv1,&dump,&dump,&dump,&dump,&dump,&dump,&dump,&trv1,&dump,&dump,&dump,&dump,&dump,&dump,&dump);*/
sscanf(n_line,"%s%lu",drop,&rcv1);
printf("\nDrop is read as: \t %s\nRx is %lu",drop,rcv1);
if(rcv1 == 0){ printf("\nError!:NULL_VALUE-RX-1: Value received for parsing is 0."); }
sleep(1);
sscanf(n_line,"%s %lu %u %u %u %u %u %u %u %lu %u %u %u %u %u %u %u", drop,&rcv2,&dump,&dump,&dump,&dump,&dump,&dump,&dump,&trv2,&dump,&dump,&dump,&dump,&dump,&dump,&dump);
if(rcv2 == 0){ printf("Error!:NULL_VALUE-RX-2: Value received for parsing is 0."); }
dspeed = rcv2-rcv1;
uspeed = trv2-trv1;
unsigned long *speeds [2];
speeds[0] = &dspeed;
speeds[1] = &uspeed;
return *speeds;
}
//==========================Main
int main(int argc,char *argv[]) {
FILE *netdev;
String networkid = malloc(10);
networkid=argv[1];
netdev = fopen(NETWORK_FILE,"r");
if (netdev == NULL) { printf("Error Opening file!"); return (-1); }
unsigned long *spd[2];
*spd = receive(netdev,networkid);
printf("\n D: %lu | U: %lu \n",*spd[0],*spd[1]);
fclose(netdev);
}
测试文件:
注意:测试文件的值稍旧,因为它使用旧的复制粘贴。
#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
char *w1,*w2,*w3,*w4,*w5;
w1 = (char*) malloc(8*sizeof(char));
w2 = (char*) malloc(8*sizeof(char));
w3 = (char*) malloc(8*sizeof(char));
w4 = (char*) malloc(8*sizeof(char));
w5 = (char*) malloc(15*sizeof(char));
unsigned long n1,n2,d1,d2,d3,d4,d5,d6,d7;
char *teststring,*devstring;
devstring = (char *) malloc(150*sizeof(char));
devstring = "enp3s0: 168010376 192508 0 0 0 0 0 547 19528703 142230 0 0 0 0 0 0";
sscanf(devstring,"%s %lu",w5,&d1);
printf("\n\nDev line parse is:\n %s RX: %lu\n",w5,d1);
}
输出
主文件
Device enp3s0 Found on Line 4
Line Input is:
enp3s0: 197678794 218123 0 0 0 0 0 617 21694353 160864 0 0 0 0 0 0
Drop is read as: <= There is usually gibberish here. Its different everytime. And sometimes its not there at all
Rx is 94544931811891
D: 94544931811891
测试文件
Dev line parse is:
enp3s0: RX: 168010376
我几乎是 C 语言的初学者(这是我第一个使用指针的程序。我仍然无法理解这些)所以肯定会以 worst/dumb 可以想象的方式完成一些事情.欢迎指正。
编辑:
所以根据@Mathieu 的回答,我尝试合并一个 return 检查 sscanf:
int assign_count = sscanf(n_line,"%s %lu %*u %*u %*u %*u %*u %*u %*u %lu %*u %*u %*u %*u %*u %*u %*u",drop,&rcv1,&trv1);
if(assign_count == 3){
printf("\nRx is %lu",rcv1);
}else { printf("\nERROR!::RECEIVE_ASSIGN_FAILURE:: Failed to assign %d values(Current: %d)",3,assign_count); }
输出: 这随机给了我两个不同的输出。
Device enp3s0 Found on Line 4
Line Input is:
enp3s0: 201330925 226694 0 0 0 0 0 790 23566091 172240 0 0 0 0 0 0
ERROR!::RECEIVE_ASSIGN_FAILURE:: Failed to assign 3 values(Current: -1)
D: 93951710999123
Device enp3s0 Found on Line 4
Line Input is:
enp3s0: 201339561 226756 0 0 0 0 0 798 23586994 172381 0 0 0 0 0 0
ERROR!::RECEIVE_ASSIGN_FAILURE:: Failed to assign 3 values(Current: 2)
Error!:NULL_VALUE-RX-1: Value received for parsing is 0.Error!:NULL_VALUE-RX-2: Value received for parsing is 0.
D: 0
在一种情况下,ret
或 assign_count
显示为 -1,在另一种情况下显示为 2。此外,在某些执行中,我遇到了 Segmentation Fault也是随机的。
您对 sscanf
的使用可能会更好:
- 在使用其结果 之前先阅读
- 知道 scanf 会忽略要读取的字段之间的额外 space,您可以在
format
参数中只写一个 - 要求
sscanf
使用%*..
忽略某些字段
sscanf
的结果
因此,您的代码将变为:
#include <stdio.h>
int main(void) {
char *lines[] = {
" lo: 4845 60 0 0 0 0 0 0 4845 60 0 0 0 0 0 0",
"enp3s0: 197557966 217836 0 0 0 0 0 591 21516707 160167 0 0 0 0 0 0",
" sit0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"
};
long unsigned int rcv2, trv2, i;
char name[256];
for (i = 0; i < 3; ++i)
{
int ret = sscanf(lines[i],"%s %lu %*u %*u %*u %*u %*u %*u %*u %lu %*u %*u %*u %*u %*u %*u %*u", name,&rcv2,&trv2);
if (3 == ret)
printf("%s, %lu, %lu\n", name, rcv2, trv2);
else
printf("Error: %d conversion(s) instead of 3\n", ret);
}
}
好的,在进一步的故障排除后,我发现 n_line
已损坏。它作为一个整体打印正确,但当我尝试解析它时,它有一些问题。
首先,我通过使用 strtok
和 for
循环打印拆分字符串来分析 searchstr
函数中的 tmpf
变量。 - 它按预期正确打印
char *wd;
wd = strtok(tmpf," ");
while( wd != NULL){
printf("::%s\n",wd);
wd = strtok(NULL," ");
}
但是当我在 n_line
上的 receive
函数中 运行 相同时,它会产生损坏的输出 - 要么打印第一个字符串,要么从该行随机打印一些数字.
解决方案:..有点
然而,当我将 tmpf
声明为 static
.
当声明为 static
时,sscanf
正确写入所有变量并且详细输出也正确。
Device enp3s0 Found on Line 4
tmpf is : enp3s0: 4054772 8380 0 0 0 0 0 131 1842262 11148 0 0 0 0 0 0
Line Input is:
enp3s0: 4054772 8380 0 0 0 0 0 131 1842262 11148 0 0 0 0 0 0
Rx is 4054772 | Tx is 1842262
我真的不知道为什么它会突然工作,但我的猜测是 static
使 tmpf
在两个函数中都保留在内存中,因此我能够在第二个功能。仍然感觉这更像是 hack 而不是实际的解决方案。
其他一些输出也被破坏,但这可能不是这个问题的一部分。
编辑:
我刚刚还找到了一个消息来源,说明了这一点: https://www.tutorialspoint.com/cprogramming/c_return_arrays_from_function.htm