What Can Happen If Printf Is Called With a Wrong Format String

What can happen if printf is called with a wrong format string?

What can happen if printf is called with a wrong format string?

Anything can happen. It is Undefined behavior!

Undefined behavior means that anything can happen. It may show you results which you expect or it may not or it may crash. Anything can happen and you can blame no one but yourself about it.

Reference:

c99 Standard: 7.19.6.1:

para 9:

If a conversion specification is invalid, the behavior is undefined.225) If any argument is
not the correct type for the corresponding coversion specification, the behavior is
undefined.

Using incorrect format specifier in printf()

When you use the incorrect format specifier to printf, you invoke undefined behavior, meaning you can't accurately predict what will happen.

That being said, floating point values are typically passed to functions via floating point registers, while integer values are typically passed on the stack. So the value you're seeing is whatever happened to be sitting on the stack.

As an example, if I put that line by itself in a main function, it prints a different value every time I run it.

If you want to print the representation of a float, you can use a union:

union {
float f;
unsigned int i;
} u;
u.f = 1.0f;
printf("%d", u.i);

What happens when I use the wrong format specifier?

what happens when I use the wrong format specifier in C?

Generally speaking, undefined behaviour.*

However, recall that printf is a variadic function, and that the arguments to variadic functions undergo the default argument promotions. So for instance, a char is promoted to an int. So in practice, these will both give the same results:

char x = 'A';
printf("%c\n", x);

int y = 'A';
printf("%c\n", y);

whereas this is undefined behaviour:

long z = 'A';
printf("%c\n", z);


* See for example section 7.19.6.1 p9 of the C99 standard:

If any argument is
not the correct type for the corresponding conversion specification, the behavior is
undefined.

How printf works in case of type mismatch with type specifier?

You could see that the code also works with %d, %x, %u format specifiers.

Why it works without any warnings ?

Because you don't have warnings enabled in your CodeBlocks.

Go to settings -> compiler and check

Enable All Common Compiler Warnings [-Wall]

And now you get:

In function 'int main()':
warning: format '%c' expects argument of type 'int', but argument 2 has type 'const char*' [-Wformat=]|

Why it even works ?

With %c, $ is the output in CodeBlocks, X is the output in Visual Studio . So, that sounds like undefined behavior.

Wrong format specifiers in scanf (or) printf

Anyways if you want the first char this way only you could do this:

#include <stdio.h>

int main()
{
printf("%c", *"Hello\n"); // Not asked in Question but still :)

return 0;
}

It prints H by dereferencing the const pointer.

Wrong format specifiers in scanf (or) printf

Variadic arguments (those matching the ellipsis, ...) are default-promoted. That means that all shorter integral types are promoted to int (or unsigned, as appropriate). There's no difference between inte­gers and characters (I believe). The difference between %d and %c in printf is merely how the value is formatted.

scanf is a different kettle of fish. All the arguments you pass are pointers. There's no default-pro­mo­tion among pointers, and it is crucial that you pass the exact format specifier that matches the type of the pointee.

In either case, if your format specifier doesn't match the supplied argument (e.g. passing an int * to a %p in printf), the result is undefined behaviour, which is far worse than being "unpredictable" -- it means your program is simply ill-formed.

why printf with %d specifier giving wrong result?

It's not specifically with printf(), the issue is caused by the erroenous call to scanf().

Quoting C11, chapter §7.21.6.2

[...] Unless assignment suppression was indicated by a *, the
result of the conversion is placed in the object pointed to by the first argument following
the format argument that has not already received a conversion result. If this object
does not have an appropriate type, or if the result of the conversion cannot be represented
in the object, the behavior is undefined.

For %d conversion specifier, the expected type of argument is

d [....] The corresponding argument shall be a pointer to
signed integer.

But, all you're supplying is a pointer to a char. Mismatch. Undefined behavior.

OTOH, for %c conversion specifier,

c Matches a sequence of characters of exactly the number specified by the field
width (1 if no field width is present in the directive).
If no l length modifier is present, the corresponding argument shall be a
pointer to the initial element of a character array large enough to accept the
sequence. No null character is added.

so using

 scanf("%c",&ch);

is correct. Alternatively, you can also use

 scanf("%hhd",&ch);    //char is signed
scanf("%hhu",&ch); //char is unsigned

If printf() is given an incorrect argument type relative to it's respective format specifier, does the C compiler attempt to implicitly convert it?

Because the printf function is variadic, any parameters after the format string are subject to the default argument promotions. This means that any type smaller than int is promoted to int and float is promoted to double. These are the only conversion that happen to the arguments.

If the arguments passed do not match what the format string expects, you invoke undefined behavior.

For example, this is valid:

float f = 1.2f;
printf("f=%f\n", f);

Because %f expects a double, and f is promoted to a double before being passed to the function.

This is not:

float f = 1.2f;
printf("f=%d\n", f);

Because a double was passed but %d is expecting to read an int.

More examples:

short s = 3;
long long x = 5;
printf("%d\n", s); // valid: s is promoted to int
printf("%d\n", x); // invalid: no promotion happens and a long long
// was passed but an int was expected

What happens when a format specifier is not given to printf?

Format specifiers in the format string are not required so:

printf("%s", "Hello world\n");

and

printf("Hello world\n");

will produce the same behavior.

However if the string in:

printf(str);

comes from an user input, you should use the %s specifier otherwise you are prone to format string attacks (the attacker could forge strings with %x to dump the stack and %n to overwrite memory).

Why does C's printf format string have both %c and %s?

Probably to distinguish between null terminated string and a character. If they just had %s, then every single character must also be null terminated.

char c = 'a';

In the above case, c must be null terminated. This is my assumption though :)



Related Topics



Leave a reply



Submit