将格式字符串作为命令行参数传递给 scanf 与对其进行硬编码

Wak*_*nka 3 c scanf

我有以下代码:

#include <stdio.h>
int main()
{
    int i;
    char c;
    char *format_string = "%d\n";
    scanf(format_string, &i);
    printf("read: %d\n", i);

    printf("Let's check what is in the input buffer:\n");
    while (scanf("%c", &c) == 1)
    {
        printf("read from input buf: %d\n", c);
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我按以下方式运行代码:

echo "5" | ./specific.out
Run Code Online (Sandbox Code Playgroud)

输出如下:

read: 5
Let's check what is in the input buffer:
Run Code Online (Sandbox Code Playgroud)

这里我有上面代码的更通用版本,我从命令行传递格式字符串:

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

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        exit(EXIT_SUCCESS);
    }

    int i;
    char c;

    char *format_string = argv[1];

    scanf(format_string, &i);
    printf("read: %d\n", i);

    printf("Let's check what is in the input buffer:\n");
    while (scanf("%c", &c) == 1)
    {
        printf("read from input buf: %d\n", c);
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我按以下方式运行代码:

echo "5" | ./general.out '%d\n'
Run Code Online (Sandbox Code Playgroud)

输出如下:

read: 5
Let's check what is in the input buffer:
read from input buf: 10
Run Code Online (Sandbox Code Playgroud)

为什么我会得到不同的输出?

dbu*_*ush 6

当您'%d\n'在命令行上指定时,您不会发送%后跟d换行符。您发送%后接着d接着\接着接着n

因此,该echo命令生成的换行符与格式字符串中的任何内容都不匹配(特别是换行符不匹配\),因此它保留在输入缓冲区中。

为了获得相同的结果,您的命令行必须如下所示:

echo "5" | ./x1 '%d
'
Run Code Online (Sandbox Code Playgroud)

附带说明一下,将格式字符串置于用户的控制之下是一个坏主意,因为这可能会导致格式字符串漏洞。格式字符串最好保留为字符串文字。

作为额外的好处,如果您使用字符串文字作为格式字符串,那么如果格式字符串与传递给它的参数不匹配,您的编译也将能够生成警告。