-1

what does struct variable contain when not used with . operator?

Conisder below program

#include<stdio.h>
typedef struct{
          char a;
          int b;
        } scratch;

int main(){
  scratch s1 = {2,4};
  printf("%p",s1); o/p 000566000
  printf(" %p",&s1); o/p 00000420
  printf(" %p",&s1.a); o/p 00000420
  return 0;
}

sturct variable s1 and its first member s1.a both return the same address when used with & but s1 returns some other value. is this garbage or what ?

what does struct s1 contain? (when I do this with oops language, object variable prints some address as far as concerned to java and there is no address operator in java).

Could anyone clear me what s1 is doing here? or simply a compiler issue?

user3205479
  • 1,443
  • 1
  • 17
  • 41
  • 3
    Your first paragraph is mainly wrong, which will make it difficult to answer this question. C doesn't have "classes", and in general, whether an object is allocated on "the stack" or on "the heap" is independent on how its type was defined. – juanchopanza Oct 07 '14 at 08:51
  • @juanchopanza yes, class members are allocated on heap and that reference address is saved to object which is allocated on stack – user3205479 Oct 07 '14 at 08:53
  • 2
    You say "yes" and then contradict what I just said. No, class members are not allocated on "the heap" I said " whether an object is allocated on "the stack" or on "the heap" is independent on how its type was defined". – juanchopanza Oct 07 '14 at 08:55
  • @juanchopanza http://docs.oracle.com/cd/E13150_01/jrockit_jvm/jrockit/geninfo/diagnos/garbage_collect.html "Java objects reside in an area called the heap" sorry I am not aware of other languages but this is what java documentation says – user3205479 Oct 07 '14 at 09:00
  • 1
    Are you aware that you tagged your question as C and not Java? – juanchopanza Oct 07 '14 at 09:04
  • @juanchopanza I have also mentioned comparison between java and c with & operator in my post. You said "class members are not allocated on heap" (you did not specify the language) also you told object is allocated on stack or heap is independent but what I studied in java, object allocation is on heap and in cpp its on stack. cpp just puts access specifiers but its not a complete OOP language as far as I concerned. – user3205479 Oct 07 '14 at 09:09
  • Are you sure that you have your output (566 and 420) the right way round. Could you cut-and-paste the actual output of the program please. – Airsource Ltd Oct 07 '14 at 09:10
  • 2
    @user3205479 Your code is C. You tagged your question C. You are asking about the address-of operator. Then all of a sudden you're talking about java? Interesting. – juanchopanza Oct 07 '14 at 09:11
  • @AirsourceLtd after reading all the answers, I have understood its compiler dependent. Thanks for your help :) – user3205479 Oct 07 '14 at 09:12
  • @juanchopanza I dont think, I intentionally talking about java. You have told class members then it made me move towards java. – user3205479 Oct 07 '14 at 09:15
  • 2
    You are really making no sense whatsoever. I'm done here. – juanchopanza Oct 07 '14 at 09:16
  • *You said "class members are not allocated on heap"* -- Wrong (like almost everything else you're claimed). *(you did not specify the language)* -- the question is tagged C so of course that's what @juanchopanza was referring to. – Jim Balter Oct 07 '14 at 09:18

5 Answers5

3

All of your printf statements are illegal.

In printf("%p",s1); type scratch is passed when void* is expected. This results in undefined behaviour.

In printf("%p",&s1); type scratch* is passed when void* is expected. This results in undefined behaviour. Use printf("%p",(void*)&s1); instead.

In printf("%p",&s1.a); type char* is passed when void* is expected. This results in undefined behaviour. Use printf("%p",(void*)&s1.a); instead.

Airsource Ltd
  • 32,379
  • 13
  • 71
  • 75
user694733
  • 15,208
  • 2
  • 42
  • 68
  • 1
    The last two aren't really undefined, they just lack the cast. But the code will work as expected on any C compiler. – Aaron Digulla Oct 07 '14 at 09:02
  • 1
    @AaronDigulla Those are undefined behaviour. Internal presentation of addresses for `void*` and `scratch*` are not necessarily same. – user694733 Oct 07 '14 at 09:05
  • 1
    @AaronDigulla "The last two aren't really undefined" -- Better check the C standard before making such claims. " the code will work as expected on any C compiler" -- that's not relevant to the question of whether it's undefined behavior. – Jim Balter Oct 07 '14 at 09:26
  • @JimBalter "A pointer to any incomplete or object type may be converted to a pointer to void", C standard 6.3.2.3§1 (both C99 and C11). – Virgile Oct 07 '14 at 09:31
  • 2
    @Virgile There's no conversion here -- missing cast. Please pay attention. And A Ltd has no idea what s/he is talking about. – Jim Balter Oct 07 '14 at 09:32
  • 1
    @Virgile Functions with variable arguments are a special case. There is no implicit conversion to `(void*)` when passing pointer argument of different type. – user694733 Oct 07 '14 at 09:33
  • @AirsourceLtd See http://stackoverflow.com/questions/1241205/are-all-data-pointers-of-the-same-size-in-one-platform ... I hope the ignorant people who downvoted this will retract their downvotes. – Jim Balter Oct 07 '14 at 09:39
  • "Functions with variable arguments are a special case" -- or functions without prototypes. – Jim Balter Oct 07 '14 at 09:40
  • @JimBalter: There are millions lines of C code like that out there. Even though the C standard states it's undefined it really isn't. Code like that will work with any modern C compiler unless you have odd memory models (like Intel's segmented memory model with short and long pointers). – Aaron Digulla Oct 07 '14 at 09:42
  • "Even though the C standard states it's undefined it really isn't." -- That is absurd beyond measure. The C Standard **determines** what "undefined" **means**. That's the last I will say to you. – Jim Balter Oct 07 '14 at 09:47
  • 1
    "I would still argue that while the OPs case may be undefined in theory, it is defined in practice." -- People like you and Aaron should not be answering C questions when you don't understand **the fundamentals**. There is no such thing as "defined in practice" -- that violates the concept of "defined". The C standard is the arbiter of what is defined. What implementations **do** is a different matter. – Jim Balter Oct 07 '14 at 09:50
  • Finally, the answer is correct and uses "undefined behavior" in the correct sense and says true things about it. People who downvoted this out of their own ignorance have acted very very badly. Goodnight. – Jim Balter Oct 07 '14 at 09:52
  • @JimBalter, you're right of course, I forgot about this point (though I'd argue that I'm probably not the only one and thus a clarification directly in the answer of user694733 rather than in a comment wouldn't hurt) – Virgile Oct 07 '14 at 12:10
2

This:

printf("%p",s1);

Is invalid and probably undefined behavior. The format specifier %p is not compatible with your struct. And GCC will tell you so if you enable warnings:

format ‘%p’ expects argument of type ‘void *’, but argument 2 has type ‘scratch’ [-Wformat]
John Zwinck
  • 239,568
  • 38
  • 324
  • 436
  • Still the question remains what the C compiler does when you put `s1` on the stack for the call to `printf()`. Does it copy the structure? – Aaron Digulla Oct 07 '14 at 09:01
  • 1
    Yes, it will copy the structure. And printf will use it incorrectly, invoking undefined behavior. – John Zwinck Oct 07 '14 at 09:05
  • Then I'd expect to see `02` and `00000004` in the output since `%p` just interprets the next element on the stack as an pointer-sized int value which it has to print as hex. This isn't what I see in the output. Why not? – Aaron Digulla Oct 07 '14 at 09:07
  • 1
    It doesn't have to necessarily be copy. Some compilers make copy on stack and pass address of that copy instead under the hood. It's legal as long as it seems to work as pass-by-value on the surface. Remember that C standard doesn't even require stack, so what happens behind the scenes is implementation defined. – user694733 Oct 07 '14 at 09:10
  • 2
    It's undefined behavior. Anything could happen. On my system I do in fact see that the low byte of the "pointer" is 2 as you expect. But maybe your system gave you a different undefined behavior. It's allowed to. And note that it comes out like `0x42ffa1b02` for me instead of `0x02` because the other bytes are not initialized at all, because the first element is only a single-byte char. – John Zwinck Oct 07 '14 at 09:10
  • @AaronDigulla "%p just interprets the next element on the stack as an pointer-sized int value" -- are pointers and ints the same size on your system? On some systems they aren't. – Jim Balter Oct 07 '14 at 09:22
  • @JimBalter: That's why I said it's in integer value with the same size as a pointer (whatever that might be on the system in question). – Aaron Digulla Oct 07 '14 at 09:30
  • @AaronDigulla I know what you said ... but you don't comprehend my question. %p expects a "pointer-sized int", but s1.a isn't necessarily one of those (and may or may not be padded). – Jim Balter Oct 07 '14 at 09:37
  • 1
    @AaronDigulla You have a char and and int, neither which is necessarily sized as a pointer, and combined they might not be sized as a pointer. There is quite likely padding between the char member and the int as well, leaving you with uninitialized bytes in the struct. In the general case, a struct can have different alignment requirements than a pointer leaving the compiler to place it differently on the stack than where a pointer would be expected to live. Even calling conventions could dictate a different layout of the stack depending on whether it's a pointer or a struct. – nos Oct 07 '14 at 09:53
  • @nos Aaron makes claims like "Even though the C standard states it's undefined it really isn't." Some people combine ignorance and arrogance in a way that makes them unreachable with reason. – Jim Balter Oct 07 '14 at 09:58
2

About the printf("%p", s1); - it is a garbage value because it (the struct) is not compatible with the format specifier %p because it is not a pointer - it is not about the compiler - it's about the function printf() and how varargs acts - notice that when you just type printf("%d"); it will print a value, a random one that was found in the memory of the stack at that moment - printf() thought you transfered 2 parameters, one format string and one value matching the format specifier so he used varargs to withdraw the variable (which is obviously not there as we didn't transfer it) and it withdrew a random garbage value. About s1 and s1.a having the same address - this is because the integer a is the first variable in the struct scratch, so when you request the address of a you request the first byte where it starts (although here it's a char so it's only one byte anyway), the struct itself (being a struct) doesn't consume some extra memory so both s1 and s1.a have the same address because s1.a is actually the first byte of the structure.

Zach P
  • 1,731
  • 11
  • 16
0

&s1 is the address of s1. &s1.a is the address of s1.a, which is the same as the address of s1 because "a" is the first element of the structure.

Now, "%p" is used to print a pointer address. s1 is the structure instance, not an address and therefore should not be printed using "%p".

0

Are you sure you have your output correct here?

printf("%p",s1) 

will take the value of s1 (i.e. the bytes it represents, something depends how you compile it, and the target machine architecture), and treat it as a pointer. It will in any case generate a compiler warning -

test.c:10:15: warning: format specifies type 'void *' but the argument has type 'scratch' [-Wformat]

For an unpacked struct, a char will occupy 4 bytes (on most systems, implementation defined). The struct will be laid out as below.

The layout in memory of s1 is therefore (on a little-endian system) 0x02 (char) 0x000000 (3 bytes padding) 0x04000000 (int)

If you print this out on a 64 bit little-endian system (64 bit pointers) it will expect 8 bytes of pointer address, smallest word first.

It will therefore print out 0x400000002 - on most modern systems IF the padding bytes are initialised to zero, or if the stack simply happens to contain zeroes. If the stack does not contains zeros, the the bytes between 4 and 2 could contain anything at all.

When you print out the address of s1 (&s1) or of s1.a (&s1.a) you are printing out the actual memory address they are stored at - the same in both cases. This is a valid thing to do.

Airsource Ltd
  • 32,379
  • 13
  • 71
  • 75
  • the padding bytes should be between the char and the int, so a possible output could be `0x4??????02`, the ? are the padding bytes which can have any value. – mch Oct 07 '14 at 09:14
  • While they *could* be any value, it is likely on many implementations that they are actually zero and I assert that this is true on the OPs system. – Airsource Ltd Oct 07 '14 at 09:25
  • Your expectations are based on faulty assumptions. On my system the output is "0x28ac02 0x28ac58 0x28ac58" – Jim Balter Oct 07 '14 at 09:30
  • +1 this is the correct answer to the quesion "what happens for `printf("%p",s1)`?" – Aaron Digulla Oct 07 '14 at 09:32
  • Fixed the padding layout (and the byte-order for the int). – Airsource Ltd Oct 07 '14 at 09:34
  • @AirsourceLtd: On my 64bit Linux system, it prints `0x43dce1602`. The leading `4` is part of the `int` field. Then we have 3 random bytes (padding isn't cleared) and then the `02`. That's why I think the ordering in your answer (`0x402000000`) is wrong - `%p` will reorder the little-endian bytes while printing. – Aaron Digulla Oct 07 '14 at 09:36
  • @AaronDigulla D'oh. Yes, fixing.... – Airsource Ltd Oct 07 '14 at 09:37