为什么我不能用动态args设置printf的输出格式?

时间:2015-05-20 07:03:32

标签: c arguments printf command-line-arguments

我想用动态参数控制printf()函数输出格式,如下面的代码所示:

    #include<stdio.h>

    int main(int argc,char ** argv)
    {
        printf(argv[1],"hello,world");
        return 0;
    }

然后我编译并运行它:

$ gcc -o test test.c
$ ./test "\t%s\n"

结果很奇怪:

\thello,world\n$

为什么"\n""\t"无效?

4 个答案:

答案 0 :(得分:9)

因为您使用的转义符(\t\n)由C编译器在字符串文字内解释,而不是由printf()解释。这样:

const char *newline1 = "\n", newline2[] = { '\n', 0 };

会在newline1newline2中生成完全相同的内容,无论这些内容是否传递给printf();无论如何,弦都在那里。

您的代码就像这样:

printf("\\t%s\\n", "hello,world");

在这里,我对特殊字符进行了双重转义,以生成一个与命令行参数具有相同实际内容的字符串,即"\t%s\n"(六个字符而不是四个字符)。

动态控制printf()的正确方法是在代码中构建格式字符串。如果你想在运行时使用类似C的转义,你需要以某种方式自己解释它们。

答案 1 :(得分:6)

C / C ++中字符串或字符文字中的序列\n单字节,数值为10(在ASCII系统上)。当在终端上输出时(尝试putchar(10)!),它只是将终端上下一个字符的输出位置设置为下一行的开头(在* nix上;在MacOS上,我想,你需要一个额外的{ {1}}或13用于回车以使输出位置在行的开头。)

类似地,\r是单个字节的符号,值为9,这使得大多数终端将光标前进到下一个制表位置。

您需要在命令行中插入这些值的单个字节。如何做到这一点取决于你的外壳;在bash中,你可以通过事先按下Ctrl-V来保持shell解释特殊字符。那输出例如一个选项卡,通过显示一些空白空间显示(而不是让shell显示可能的字符串延续或bash中的任何选项卡)。单引号或双引号中的bash字符串可以包含换行符而无需进一步努力 - 只需按Enter即可。

以下是使用bash在cygwin终端中运行的示例。我按下指示位置的指示键;在第二行关闭单引号后,我像往常一样用[return]完成了命令。

\t

在我用单引号分隔的字符串中按Enter键后,shell输出第二行中的pressed Ctrl-v,[TAB] here | pressed [return] there v v $ ./printf-arg.exe ' %s > ' hello,world 。 (在字符串中插入换行符)。这表示正在编辑的字符串在该行上继续。

另外,在潜在的恶意环境中以这种方式使用命令行参数可能是不安全的。精心设计的字符串可以访问不打算访问的内存,例如重定向返回地址,从而破坏程序。

答案 2 :(得分:4)

这是因为编译器处理转义序列,如"\n"等,它只在字符串或字符文字中处理。

答案 3 :(得分:3)

如果您将解释的“\ t%s \ n”传递给命令它将起作用。但是在shell中构造这样的字符串很棘手。我知道最简单的方法是:

./test $'\t%s\n'

请参阅$'magick'

man bash的ANSI引用