我想用动态参数控制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"
无效?
答案 0 :(得分:9)
因为您使用的转义符(\t
和\n
)由C编译器在字符串文字内解释,而不是由printf()
解释。这样:
const char *newline1 = "\n", newline2[] = { '\n', 0 };
会在newline1
和newline2
中生成完全相同的内容,无论这些内容是否传递给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'