警告:格式字符串在字符串体中包含'\ 0'[-Wformat]

时间:2016-01-27 19:51:17

标签: c string system quoting

我的代码中有一个使用awk的system()命令。我无法弄清楚如何解决\x00十六进制值的问题。显然他们需要以不同的方式被终止,但这超出了我所知道的范围。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

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

    char command[128];
    snprintf(command, sizeof(command), "awk '{ gsub (/\xAB\x00\x00\xBC/,\"\xBC\x00\x00\xAB\") ; print }' %s", argv[1]);
    system(command);

}

警告/错误:

>  test.c:8:56: warning: format string contains '\0' within the string body [-Wformat]
>  snprintf(command, sizeof(command), "awk '{ gsub (/\xAB\x00\xBC/,\"\xBC\x00\x00\xAB\") ; print }' %s", argv[1]);
>  /usr/include/secure/_stdio.h:57:62: note: expanded from macro 'snprintf'
>  __builtin___snprintf_chk (str, len, 0, __darwin_obsz(str), __VA_ARGS__)
                                                              ^
  1 warning generated.
  sh: -c: line 0: unexpected EOF while looking for matching `''
  sh: -c: line 1: syntax error: unexpected end of file

很抱歉,如果之前有人询问,我在搜索中找不到相关信息,但是感谢...

2 个答案:

答案 0 :(得分:5)

考虑C字符串文字"\xAB"。此字符串文字包含一个字节,而不是4.类似地,"\x00"是一个字符串文字,其中包含一个空字节的字节。 Clang警告你,因为空字节结束了C字符串 - 后面的每个字符都会被snprintf等库函数忽略。

在你的awk代码中,有一个awk字符串文字,用双引号括起来。您编写了…\"\xBC\x00\x00\xAB\"…,在双引号前面加了反斜杠,因为否则双引号会被解释为结束C字符串文字。同样,如果你想在awk代码中更准确地使用反斜杠(更确切地说,在shell命令中),你需要在它前面加上另一个反斜杠。换句话说,你需要加倍反斜杠。

snprintf(command, sizeof(command), "awk '{ gsub (/\\xAB\\x00\\x00\\xBC/,\"\\xBC\\x00\\x00\\xAB\") ; print }' %s", argv[1]);

请注意您的程序还有另一个引用问题:它将其参数解释为一段shell代码,而不是文件名。如果文件名不包含任何shell特殊字符,则两者仅重合。例如,./your_program Jack.txt将起作用,但不起作用./your_program "O'Leary.txt"。要使其工作,您需要按下参数以保护shell特殊字符。

(另一个问题是你没有检查snprintf是否成功。它可能会溢出 - 你应该根据参数的长度动态分配必要的大小(不要忘记考虑额外的引用)如果参数包含特殊字符)。)

答案 1 :(得分:2)

C字符串文字中的字符序列'\''x''0''0'表示数字值为零的单个char。因此,由两个字符串文字char"\x00"表示的"\0"数组具有相同的大小和内容:两个char s(包括终结符),均为零。当用作C字符串时,两者都等效于空字符串,因为索引零处的零字符用作字符串终止符。

您的编译器警告您传递给snprintf()的字符串文字包含内部空字节(事实上它有两个),这可能会导致它不按您的意图解释。如果你的意思是将字符串中的\xhh序列视为四个文字字符的序列,那么你必须加倍反斜杠:

    snprintf(command, sizeof(command), "awk '{ gsub (/\\xAB\\x00\\x00\\xBC/,\"\\xBC\\x00\\x00\\xAB\") ; print }' %s", argv[1]);