Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can printf result in undefined behavior? [duplicate]

Tags:

c++

c

int main() 
{
  unsigned int i = 12;
  printf("%lu", i); // This yields a compiler warning
}

On a 32 bit platform, does using printf with an int using %lu result in garbage?

like image 601
bryantism Avatar asked Apr 25 '14 07:04

bryantism


3 Answers

Only the statement "32 bit platform" doesn't mean that int and long both have 32 bits, as well as their unsigned counterparts.

So yes, indeed this can happen if unsingned long, what %lu is made for, is longer than unsigned int.

But even if the lengths are equal, the types are not compatible, so formally it is undefined behaviour.

like image 148
glglgl Avatar answered Oct 22 '22 18:10

glglgl


If the required type and the given type are not compatible, you have undefined behavior. It's entirely legal for a compiler to pass type information with the value when passing a vararg, and exploit it in va_arg (although I don't know of any which do, probably for historical reasons).

As for practical effects in your particular case, "%lu" expects an unsigned long. The only other type which is compatible is long, and then only if the actual value of the long is non-negative. Passing it an int is undefined behavior, although it might work. (On most 32 bit platforms, int and long have the same size and representation.)

like image 4
James Kanze Avatar answered Oct 22 '22 18:10

James Kanze


honestly I do not understand why you should use the %lu in place of %u since you are working with an int.

%lu should be used (in its very basic explanation) for unsigned long.

It will most probably print garbage if your compiler uses (and of course it does in 99% of the situation) different storage size for int and long.

For instance, according to C standard, an unsigned int is, in terms of storage size "At least 16 bits in size. " while unsigned long is "At least 32 bits in size."

Now, let's take as an example 16 bits for int and 32 bits for long and lets' consider a untypical example where the memory is all zeroed at the moment you run the program.

You value 12 is represented in memory as:

00000000 00001100

and if you would print with an %u would result in 12:

In place, if instruct printf to print as %lu it would result that the memory taken in the printf is:

00000000 00001100 00000000 00000000

which corresponds to the long value of 786432

Edit: Passing the value of the variable to the printf function (and not the pointer (and the size) of the variable) makes the code working anyway. My previous "explanation" was mostly to explain why the warning is raised and why it is "typically" a wrong approach.

like image 1
Maurizio Benedetti Avatar answered Oct 22 '22 17:10

Maurizio Benedetti