tags:

views:

238

answers:

4

The Code used

#include<stdio.h>

struct st
{
 char a;
 short c;
 int b;
};

struct st s1;
int main()
{
        printf("%p %p \n",(&s1.b)-1, &s1);
}

If I print the address of &s1.b it prints 0x804a01c and &s1.b-2 prints 0x804a018 why it is printing same address 0x804a01c if i select &s1.b-1 ?

+7  A: 

There's probably something wrong with your printing code.

#include <stdio.h>

struct st
{
 char a;
 short c;
 int b;
};

struct st s1;

int main() {
    printf("%p\n", (void*)(&s1.b));
    printf("%p\n", (void*)(&s1.b - 1));
    printf("%p\n", (void*)(&s1.b - 2));
}

Output:

0x403024
0x403020
0x40301c
Steve Jessop
right: -1 or -2 times sizeof(int)
stacker
declare the struct s1 as global
C Learner
@C Learner: Declaring `s1` as global will not change the behavior (pointer arithmetic is defined very clearly and there is no part of the specification that allows implemenation-specific details to be intervening here).
Jason
@C Learner: Why would that matter?
Prasoon Saurav
It is behaving differently if i change this into local.. I am using gcc
C Learner
What do you mean it's behaving differently? It prints different addresses (that's fine) or it exhibits the mysterious behavior you were describing in your OP?
Jason
Maybe he is on a 64-bit cpu, then using %x is wrong. The right choice is %p.
quinmars
@quinmars: good point. @C Learner: changed as requested.
Steve Jessop
+1  A: 

If the address of s1.b is 0x804a01c, then &s1.b-2 should be 0x804a014 (assuming that int is 4 bytes), not 0x804a018. Perhaps you made a mistake when you reported the address?

kusma
You mean 4 bytes, not 32 bit :-). 4 bytes == 32 bit iff `CHAR_BIT == 8`.
Alok
Of course. Thanks for the correction.
kusma
+2  A: 
Alok
A: 

Thank you for posting your code. Now I see the issue. It is because of padding. To wit:

printf("sizeof(char): %d\n", sizeof(char));
printf("sizeof(short): %d\n", sizeof(short));
printf("sizeof(int): %d\n", sizeof(int));
printf("sizeof(struct st): %d\n", sizeof(struct st));

On my machine this prints

1
2
4
8

You might think, shouldn't sizeof(struct st) be 1 + 2 + 4 = 7? That's certainly a reasonable thought but because of alignment issues there is padding between a and c. Therefore, in memory, the struct looks like the following (relative to the first byte of the struct):

0x00000000: char                 a
0x00000001: padding
0x00000002: first byte of short  c
0x00000003: second byte of short c
0x00000004: first byte of int    b
0x00000005: second byte of int   b
0x00000006: third byte of int    b
0x00000007: fourth byte of int   b

Consequently (relative to &s1):

&s1.b - 1 is ((long)&s1.b) - sizeof(int) = 4 - 4 = 0 = &s1

This is why both &s1 and &s1.b - 1 will print the same address. In particular if

&s1 = 0x804a01c

then

&s1.b = 0x804a01c + 0x00000004 = 0x804a020

and

&s1.b - 1 = 0x804a020 - 0x00000004 = 0x804a01c

and

&s1.b - 2 = 0x804a020 - 0x00000008 = 0x804a018

Note, finally, that this is implementation-specific behavior. This is not portable!

Jason