3

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.

4
  • Structure variables don't behave as arrays, if that helps. Commented Jun 23, 2010 at 5:48
  • I can't believe that your compiler didn't give you at least a warning on that code. Mine, not very surprisingly gives bogus.c:26: warning: format '%d' expects type 'int', but argument 2 has type 'struct temp' Commented Jun 23, 2010 at 8:56
  • I was using gcc 2.95 version of the compiler and it didn't give me any warning Commented Jun 23, 2010 at 9:36
  • This is the correct answer to these kinds of questions Commented May 28, 2019 at 12:01

4 Answers 4

7

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);
Sign up to request clarification or add additional context in comments.

7 Comments

Does it mean we can pass structure variable to printf and print all the members of structure if we frame the format string properly??
Yes and no - you have to watch out for padding. For example, struct { char ; int } probably has empty space between the char and int to align properly. And it will most likely contain rubbish. What you should do is pass &obj and print %d %d on obj->a obj->b.
@paxdiablo: you mean obj.a and obj.b
No, because I'm passing in the pointer to the structure, not the structure itself.
@paxdiablo: How do you mean? The typical way to print these would be printf("%d and %d\n", obj.a, obj.b), right?
|
7

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’

Comments

5

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.

Comments

1

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.