如何使用sscanf将一行读入5个变量

时间:2017-02-03 02:46:30

标签: c scanf

我正在尝试编写将在格式化行中读取的内容并将其分解为变量。

该行将如下所示

label:    add    $t0,$t1,$t2

格式是

label:[tab]instruction[tab]$rd,$rs,$rt

它是一个标签,后跟一个冒号,一个标签,一条指令,一个标签,然后是一个寄存器列表。我声明了保存标签,指令,目标寄存器,第一个寄存器和源寄存器的字符串。这些变量名为lLabel,lInst,lrs,lrt和lrd。

我所做的代码是

sscanf(line, "%[^:]:\t%[^\t]\t$%[^,],$%[^,]$,%[^\n]", lLabel, lInst, lrd, lrs, lrt);

我的想法是将所有内容读取到冒号,将其存储在lLable中。匹配冒号,匹配选项卡。读取所有内容到tab,存储在lInst中。匹配标签,匹配$ sign。阅读逗号,存储在rd。匹配逗号和$。阅读所有内容以逗号,存储在rs中。匹配逗号和$。然后读取所有内容到换行符并在rt中存储。

出于某种原因,它会像这样填充

Label: me
Instruction: add
rs: t1
rt:
rd: t0

我的格式错误在哪里?

编辑:我已将其更改为

sscanf(line, "%[^:]:\t%[^\t]\t$%[^,],$%[^,],$%[^\n]", lLabel, lInst, lrd, lrs, lrt);

不是像

那样填充
Label: me
Instruction: add
rs: t1t2t0
rt: t2t0
rd: t0

1 个答案:

答案 0 :(得分:3)

正如评论中所指出的那样,您的sscanf格式字符串中会出现拼写错误以及是否为 nul-terminator 提供足够空间的问题将放在最后由sscanf解析的每个字符串。

通过检查sscanf到<{1}}的返回,完全无法验证 sscanf次转化的结果。确保实际发生5次转化。在盲目处理标签,指令和rX变量中可能存在垃圾的情况之前,必须验证转换。

另一个小问题是如何处理rt转换说明符(例如%[^\n])。虽然可能适用于$t2之后没有其他空格或字符的每种情况,但它的限制性要比它需要的要严格得多。由于默认情况下%s将提供直到第一个空白字符(包括'\n')的转换,因此您只需使用{{{}}即可在换行符之前防止杂散空间1}}作为最终转换说明符,例如

%s

最后,您需要提供一些处理 if (sscanf (buf, "%[^:]:\t%[^\t]\t$%[^,],$%[^,],$%s", label, inst, rd, rs, rt) == 5) printf ("label: %s\ninst : %s\nrd : %s\nrs : %s\nrt : %s\n\n", label, inst, rd, rs, rt); 转换过程失败的行的方法。在这种情况下你如何以及你做了什么取决于你,但你需要防止转换失败。

将它们放在一个简短的例子中,您可以执行类似于以下操作的内容,它将读取并转换作为程序的第一个参数提供的文件名中的单独行中包含的每个sscanf(或者来自{{ 1}}如果没有提供文件名)。一个简单的label:[tab]instruction[tab]$rd,$rs,$rt用于声明代码中使用的各种字符串长度的常量。

stdin

示例输入文件

enum

示例使用/输出

#include <stdio.h>

/* constants for max 'rX', 'label/inst' and chars in line */
enum { MAXR = 8, MAXL = 32, MAXC = 128 };

int main (int argc, char **argv) {

    char buf[MAXC] = "",    /* initialize variables */
         label[MAXL] = "", 
         inst[MAXL] = "",
         rd[MAXR] = "", 
         rs[MAXR] = "", 
         rt[MAXR] = "";
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
        return 1;
    }

    while (fgets (buf, MAXC, fp))   /* read each line */
        /* (you should check that a complete line was read here) */
        /* validate parse into label, inst, rd, rs, rt */
        if (sscanf (buf, "%[^:]:\t%[^\t]\t$%[^,],$%[^,],$%s",
                    label, inst, rd, rs, rt) == 5)
            printf ("label: %s\ninst : %s\nrd   : %s\nrs   : %s\nrt   : %s\n\n",
                    label, inst, rd, rs, rt);
        else    /* handle error */
            fprintf (stderr, "error: invalid conversion.\n\n");

    if (fp != stdin) fclose (fp);     /* close file if not stdin */

    return 0;
}

仔细看看,如果您有任何其他问题,请告诉我。