为什么我应该在 scanf() 系列成员中加入一个长度修饰符作为参数?有什么好处?带有长度修饰符的 scanf 有什么作用?

Why i should incorporate a length modifier as argument in scanf()-family members? What is the benefit of? What does scanf with the length modifier do?

可以选择将长度修饰符作为 scanf() 或其家族成员之一的语句的参数。

为什么我应该在语句中准确地实现一个长度修饰符,无论我是否已经将赋值变量声明为,例如 long int,是否正确?

我完全不明白为什么我应该这样做,并且没有看到包含它和不使用长度修饰符的输出之间的任何区别。

例如l里面的(ell)%2ld:

long int i;
fscanf(stdin,"%2ld",&i);

我明白长度修饰符是什么,但不知道实现它的原因是什么。

我做了一些研究,甚至在 C99 中,但找不到任何关于它真正详细功能的详细描述。

关于这个site是这样说的:

length (-modifier)

One of hh, h, l, ll, j, z, t, L (optional). This alters the expected type of the storage pointed by the corresponding argument (see below).

这是否意味着长度修饰符改变了赋值变量的类型,如果它实际上不匹配用转换说明符定义的格式值?

带长度修饰符的 scanf() 到底有什么作用?

有什么好处?

非常感谢您的聆听。

编辑:

我很抱歉假设这是显而易见的,但 "don't forget to ignore the warnings" 没有被认真对待。事实上,我认为这将是重新编写程序的唯一理由。


编译以下程序(不要忘记忽略警告!):

#include <stdio.h>

int main ()
{
    long int i;
    long int j;
    scanf("%d", &i);
    scanf("%ld", &j);
    printf("i == %ld\n", i); 
    printf("j == %ld\n", j);
    return 0;
}

运行 并提供一个大于 2147483647 的整数两次,您就会得到答案。


剧透:

我用 4294967297 做了这个,打印了以下内容:

i == 1
j == 4294967297

当然,答案是特定于体系结构的,我假设您的机器以 32 位存储 int。但是如果有理由使用 long int 来存储数字,你最好使用长度修饰符(如果它没有什么区别,你不需要使用 long int ).

但要更明确地回答您的问题:

Does that mean that the length modifier alters the type of the assigned variable, if it is not actually matching to the format value defined with the conversion specifier?

没有。正如您在尝试存储一个不带长度修饰符的 long int 的值时所看到的那样,就像您正在存储 int 一样(甚至表现得好像发生了溢出)。如果您使用 %ldscanf 来尝试将值存储到 int 变量中,则不会抛出段错误,这可能会导致不好的事情。编译以下内容(并且为了实验而不得不忽略警告):

#include <stdio.h>

int main ()
{
    int k[2] = {0,0};
    printf("k[0] == %d\n", k[0]);
    printf("k[1] == %d\n", k[1]);
    scanf("%ld", &k);
    printf("k[0] == %d\n", k[0]);
    printf("k[1] == %d\n", k[1]);
    return 0;
} 

和运行它通过输入4294968300打印出来:

k[0] == 0
k[1] == 0
4294968300 
k[0] == 1004
k[1] == 1

意味着臭名昭著的 scanf 已经将过去的 k[0] 写入 k[1] 中,完全没有引起注意!

Why should I [sic] implement a length modifier in the statement exactly, whether I've [sic] already declared the assigning variable as, for example long int, proper or not?

I quite do not understand why I [sic] should do so and do not see any difference in the output between including it and doing it without length-modifier.

我认为上面的例子应该给你一个强烈的动机,让你在 scanf 调用中尝试使用不匹配的长度修饰符进行编译时不要忽略警告。否则,您甚至可能 运行 存在安全风险。

scanf 需要知道它正在写入什么类型的对象。假设,在这个 C 实现中,char 是一个字节,short 是两个字节,int 是四个字节,long int 是八个字节。 scanf 接收的参数是一个指针,但 scanf 知道该指针指向什么的唯一方法是通过格式字符串。

如果参数指向 long int,则 scanf 需要向该位置写入八个字节。如果它指向 short,那么 scanf 需要向该位置写入两个字节而不是八个字节。

长度修饰符只是告诉 scanf 类型的代码的一部分。我们可以编写一个代码,其中 d 代表 intD 代表 long intS 代表 short int,并且很快。或者我们可以制作其他代码。很简单,我们选择的代码使用d代表inthd代表short intld代表long int,所以没有。

另一种选择可能是将有关目标类型的信息与有关要解析的内容的信息分开。 d 表示 int 和“默认读取十进制”。更简洁的设计可能有一个代码用于类型(shortint 等)和另一个代码用于输入格式(十进制、八进制、十六进制、其他)。

指针本身也可能根据其指向的事物的类型而具有不同的表示形式。这在现代 C 实现中是不常见的,但是是可能的。所以 scanf 使用长度修饰符既可以知道它正在写入什么类型的对象,也可以知道传递给它的是什么类型的指针。