tags:

views:

110

answers:

4

Hi All,

I was trying a program to understand the behavior of structure variable,

Sample code:

struct temp
{
   int a;
   int b;
}obj;

int main()
{
   obj.a = 10;
   obj.b = 7;
   /* to see whether obj and &obj both are same 
    * I was verifying whether structure variables behave as arrays
    */
   printf("%d -- %p",obj,&obj); 
   return 0;
}

I was expecting output to be 10 and address of obj But to my surprise, Actual output is 10 and 00000007

This is bugging me a lot now!!!

Could anyone please help me understand why printf is taking second member and printing its value.

+7  A: 

This happens because the first parameter is expected to have 4 bytes (an int) but it has 8 bytes (struct obj).

When you pass obj to printf function it will place on the stack the whole obj structure (including b member). So when printing it will take the first 4 bytes on the stack for 1st parameter (obj.a) and the next 4 bytes on the stack (obj.b) for 2nd parameter.

Check this out:

printf("%d %p %p\n", obj, &obj, &obj);
Daniel Băluţă
Does it mean we can pass structure variable to printf and print all the members of structure if we frame the format string properly??
udpsunil
paxdiablo
@paxdiablo: you mean obj.a and obj.b
chpwn
No, because I'm passing in the pointer to the structure, not the structure itself.
paxdiablo
@paxdiablo: How do you mean? The typical way to print these would be printf("%d and %d\n", obj.a, obj.b), right?
unwind
Sorry, bods, I meant when passing obj to another function (i.e., not printf) and then printf'ed from there. I should have read the question more closely before I added that comment. You're right inasmuch as obj.a and obj.b should be passed directly to printf.
paxdiablo
-1 for not correcting the error of passing a struct to a %d format in printf in the first place
Jens Gustedt
+6  A: 

Because you're pushing obj onto the stack. In other words, you're pushing the 10 and 7 integers onto there and one of them is being used for the %d, the other for the %p. The actual pointer isn't being used at all.

Change the line to:

printf("%d %d -- %p\n",obj,&obj);

and you'll get something like:

10 7 -- 0x804a01c

which has the correct address:

Here's a picture to help out:

What you push                 What printf uses
               +------------+
     /         |         10 |      %d
obj <          +------------+
     \         |          7 |      %p
               +------------+
&obj           | 0x80001234 |      not-used
               +------------+

I've seen similar problems when people pass a long to printf with the %d integer format specifier. The %d only uses the first part of the long and the second part screws around with all the other arguments. See here for details.

That's why gcc has those nice little warming messages that pop up when you mismatch types with specifiers in the printf family of functions:

qq.c: In function ‘main’:
qq.c:14: warning: incompatible implicit declaration of built-in function ‘printf’
qq.c:14: warning: format ‘%d’ expects type ‘int’, but argument 2
                  has type ‘struct temp’
paxdiablo
+1  A: 

The printf function takes the variable number of arguments. This means that it doesn't know which parameters you passed to it at compile time. Instead it tries to realize this at runtime by analyzing the format string you've passed.

printf("%d -- %p",obj,&obj);

The above code pushes the obj structure by value, which has a size of two integers. Plus its address, which consumes a size of one more integer (assuming 32bit architecture).

On the other hand according to the format string you had to pass it one integer, and one address.

You just confused it. It considered the second struct member b to be the second parameter passed, and printed it as the pointer. This explains the 00000007.

This is what you had to do:

printf("%d -- %p",obj.a,&obj);
valdo
+3  A: 

You might spend a lot of time trying to figure out why your printf prints what it prints and even understand everything, only to discover later, in your next experiment, that the explanation that was perfectly clear to you no longer works and you have to start everything from scratch.

The real and universally applicable explanation in this case is that your code produces undefined behavior. You specified a %d format specifier for the printf function. That means that the corresponding argument must have type int, only int and nothing else than int. Instead of an int you supplied an object of type struct temp. struct temp is not an int. Once you did that, the behavior of your code is undefined. It can print absolutely anything for no meaningful reason whatsoever. It can print nothing. It can crash. Formally, it can even format your hard drive. The behavior is undefined. Which means that even if you manage to "understand" the behavior of your program today, it might randomly change tomorrow just because the weather has changed, the date on the calendar has changed or the version of your compiler has changed.

In short, your code makes no sense (specifically because of the issue with the format specifier). Trying to pick apart the behavior of a meaningless code is a waste of time.

AndreyT