-5

I was going through scope rules questions and all and then got a code snippet, below:

#include <stdio.h>
int main()
{
  int x = 1, y = 2, z = 3;
  printf(" x = %d, y = %d, z = %d \n", x, y, z);
  {
       int x = 10;
       float y = 20;
       printf(" x = %d, y = %f, z = %d \n", x, y, z);
       {
             int z = 100;
             printf(" x = %d, y = %f, z = %d \n", x, y, z);
       }
  }
  return 0;
}

If I change the last print to:

printf("x = %d, y = %d, z = %d \n", x, y, z);

I get the following output, which I don't understand: (Ideone link)

x = 10, y = 0, z = 1077149696

So, could you explain why is z printing that value?

Bill Lynch
  • 80,138
  • 16
  • 128
  • 173
crazy_Fish
  • 78
  • 4
  • 1
    My assumption is because `printf` uses `vargs`, and expect `%d` for a `float y`, it reads the first 4 bytes of the float which is 0, and leaves the latter 4 bytes to the next `%d` which is z, so z has an undefined value printed. – SwiftMango Sep 19 '14 at 05:27
  • 2
    This code is not identical to the example in ideone. – Galik Sep 19 '14 at 05:28
  • -1 This code totally works and is not the same as the code in ideone from which you took the results. The ideone code has a bug. – Galik Sep 19 '14 at 05:34
  • "I thought, what if the innermost print was this" -- I thought, what if I cut a hole in the top of my head and poured acid in ... what might happen? – Jim Balter Sep 19 '14 at 05:35
  • 1
    "This code is not identical to the example in ideone." -- Reading comprehension? The question contains the alteration. "Here's your code on ideone" -- no, that's the code before the alteration. – Jim Balter Sep 19 '14 at 05:37
  • General problem solving hint: If you think a problem is caused by X, but there are also factors Y and Z to consider, first remove X to test if your hypothesis is true. Here, you can plug numbers into a `printf` without the scope blocks, that will tell you that the problem has nothing to do with scopes. – juanchopanza Sep 19 '14 at 05:38

3 Answers3

9

x, y, and z are resolved to most local definitions.

When you use incorrect printf % specifier, the behaviour is undefined.

y is float but you are using %d to print it (in later line).

printf uses varargs and once you corrupt the stack by using incorrect specifier (%d instead of %f in this case), stack is corrupted and incorrect interpretation of stack data (at incorrect offset) would cause many painful surprises.

Decoding This UB

This is what might be happening on your machine (One possible explanation). Because of default argument promotion, bit pattern (in hex) 0x4034000000000000 is being pushed to stack for 20.0f. Sizeof int on your little-endian machine is 4 bytes. When you print float as int your machine 0x00000000 is consumed and interpreted as int which prints first 0, later %d consumes 0x40340000 interpret it as int and prints 1077149696. Final 100 (0x00000064) is left in stack unconsumed and printf returns.

But never rely on this and always write a code for which the behaviour is well defined.

Mohit Jain
  • 30,259
  • 8
  • 73
  • 100
  • 1
    I think so, at least looking at the code in the question, the `printf` format strings look OK. Are you actually referring to the code in the link? BTW here's the code from the question on ideone: http://ideone.com/k6TCB7 – juanchopanza Sep 19 '14 at 05:32
  • 1
    The code just after the line `I thought, what if the innermost print was this:` in the question. – Mohit Jain Sep 19 '14 at 05:35
  • OK, the question is quite unclear. I changed my down-vote to an up-vote for this reason. – juanchopanza Sep 19 '14 at 05:36
  • @JimBalter I saw 3 or 4 downvotes and panicked and deleted my answer but discovered nothing wrong. So I undeleted the answer and added more info. – Mohit Jain Sep 19 '14 at 07:32
2

@mohit-jain is correct.

Using the wrong format specifier yields incorrect parameter interpretation on the stack, resulting in undefined and compiler specific behavior.

Note that on a modern compiler, like gcc or clang, it will complain that your format specification is wrong:

$ clang test.c 
test.c:12:54: warning: format specifies type 'int' but the argument has type 'float'
      [-Wformat]
             printf(" x = %d, y = %d, z = %d \n", x, y, z);
                                  ~~                 ^
                                  %f
1 warning generated.
Rich
  • 640
  • 5
  • 12
0

z = 1077149696
Using %d to print float values is undefined behaviour.
Use "%f" instead

  1. All the variables you have used have storage type "Auto" or "Automatic".
  2. The scope of the automatic variable lies inside the block in which it is declared.
  3. If there are nested blocks, then the variable declared in the outermost block will be visible to all other blocks.
  4. In case if a block has a declared a variable that matches with the one declared in outer blocks, then it will overwrite the outer variable "in its block" i.e.(locally).

To sum up : Automatic variables are local to the block in which they are declared.

Abhishek Choubey
  • 883
  • 6
  • 16