1

There is the optional opportunity to incorporate a length-modifier as argument to the statement of scanf() or one of its family members.

Why should i implement a length modifier in the statement exactly, whether i´ve already declared the assigning variable as, for example long int, proper or not?

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

For example, the l (ell) inside %2ld:

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

I understand what the length modifier is but not what the reason is for implementing it.

I did a bit of research, even in C99, for it but can´t find any detailed description for what it really does in detail.

On this site is stated:

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).

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?

What does scanf() with the length modifier do exactly?

What is the benefit of?

Thank you very much for take a listen.

  • If length is known up front, there is no need to scan for terminating null byte. – Jesper Juhl Oct 26 '19 at 18:22
  • It could prevent type mismatches where it tries to stuff 32 bits into a short int. – Dave S Oct 26 '19 at 18:28
  • %d is UB, it probably works for you because sizeof(long) == sizeof(int) in 32-bit code. Not necessarily the case in 64-bit code. Don't get confused by type promotion, which allows you to be sloppy for printf(), pointers don't get promoted. – Hans Passant Oct 26 '19 at 20:40

2 Answers2

2

scanf needs to know what type of object it is writing to. Suppose, in this C implementation, a char is one byte, a short is two bytes, an int is four bytes, and a long int is eight bytes. The argument scanf receives is a pointer, but the only way scanf knows what that pointer points to is via the format string.

If the argument points to a long int, then scanf needs to write eight bytes to that location. If it points to a short, then scanf needs to write two bytes and not eight to that location.

The length modifiers are simply part of a code that tells scanf about the types. We could have made a code where d stands for an int, D stands for a long int, S stands for a short int, and so on. Or we could have made other codes. It is simply that the code we chose uses d for int, hd for short int, ld for long int, and so no.

Another option might have been to separate the information about the destination type with the information about what to parse. d means both int and “read decimal by default”. A cleaner design might have had one code for the type (short, int, and such) and another code for the input format (decimal, octal, hexadecimal, something else).

It is also possible that the pointer itself has a different representation depending on the type of thing it points to. This is unusual in modern C implementations but is possible. So scanf uses the length modifier both to know what type of object it is writing to and what type of pointer has been passed to it.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • But what would be the result if the types are significant different; assuming the type of the object pointed to is `int` and the assigning value is of `long` type, and the compiler would let it pass? Would the program write an overflow of data beyond the bounds of the variable´s allocated space in memory, which is official classified as undefined behavior? Should i also ever incorporate the length modifier if both, the object pointed to and the assigning value have no difference in type? Why should i always and ever implement the length modifier? – RobertS supports Monica Cellio Oct 27 '19 at 09:25
  • 1
    @RobertS: When a program has mismatches between argument types and format specifiers, compilers of good quality will warn you (unless the format string is not a constant and the compiler cannot determine the format specifiers). If you persist in compiling and executing such a program in spite of the warning, it may misbehave, because `scanf` will, typically, write data outside the given object. All you need to do with the length modifier is match it to the type of the argument you pass. – Eric Postpischil Oct 27 '19 at 09:36
  • So in one sentence: Everyone should always provide the length modifier, if he/she is implementing scanf() or one of its family members for the purpose of keeping secure programs. – RobertS supports Monica Cellio Oct 27 '19 at 09:44
  • 1
    @RobertS: You need a length modifier if the argument type is not the default for the format specifier. You do not need a length modifier if the argument type is the default for the format specifier (such as `int` for `%d`). – Eric Postpischil Oct 27 '19 at 09:59
  • @RobertS see my answer, I confirmed there yesterday exactly what Eric is warning you against – gstukelj Oct 27 '19 at 12:21
1

EDIT:

I apologize for assuming this will be obvious, but "don't forget to ignore the warnings" was not to be taken seriously. In fact, I think this would be a reason alone to re-write the program.


Compile the following program (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;
}

Run it and supply an integer higher than 2147483647 two times and you'll get your answers.


SPOILER:

I did this with 4294967297 and the following got printed out:

i == 1
j == 4294967297

Of course the answer is architecture specific and I assumed your machine stores int in 32 bits. But if there's a reason to use long int in order to store a number in it, you better use a length modifier (if it doesn't make a difference, you don't need to use a long int).

But to answer your questions a bit more explicitly:

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?

No. As you saw when trying to store a value that should fit into a long int without the length modifier will act as if you're storing into an int (even behaving as if an overflow occurred). If you use %ld with scanf to try to store a value into an int variable there's no segfault thrown, and this can lead to bad things. Compiling the following (and having to ignore the warning for the sake of the experiment):

#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;
} 

and running it by inputting 4294968300 prints out:

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

meaning that the notorious scanf has written past k[0] into k[1] completely unnoticed!

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.

I think the examples above should give you a strong incentive to not ignore the warnings when trying to compile with mismatched length modifier in a scanf call. Otherwise, you might be even running a security risk.

gstukelj
  • 2,291
  • 1
  • 7
  • 20
  • 1
    "don't forget to ignore the warnings" - that's *horrible* advice, *always*. – Jesper Juhl Oct 26 '19 at 18:38
  • @JesperJuhl I was being sarcastic – gstukelj Oct 26 '19 at 18:39
  • @JesperJuhl That is absolutely correct. But this statement just belong to the proper explanation of an answer to my question, practicated on one "dummy"-program. This program was not intended to use it beyond this purpose, so i think the statement with the ignore warnings was absolutely appropriate here, as regards this is a very good answer to my question. – RobertS supports Monica Cellio Oct 27 '19 at 13:09