C Learner
C Learner

Reputation: 2337

struct pointer manipulation

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 ?

Upvotes: 0

Views: 1455

Answers (4)

jason
jason

Reputation: 241779

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!

Upvotes: 0

Alok Singhal
Alok Singhal

Reputation: 96241

Most likely you're printing it wrong:

#include <stdio.h>

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

int main(void)
{
    printf("s: %p\n", (void *)&s);
    printf("s.a: %p\n", (void *)&s.a);
    printf("s.b: %p\n", (void *)&s.b);
    printf("s.b-1: %p\n", (void *)(&s.b-1));
    printf("s.b-2: %p\n", (void *)(&s.b-2));
    return 0;
}

Prints for me:

s: 0x100001068
s.a: 0x100001068
s.b: 0x10000106c
s.b-1: 0x100001068
s.b-2: 0x100001064

Things to note:

  • Pointer to struct == pointer to struct's first element (guaranteed by the C standard),
  • I am printing the pointers with "%p" format string. "%p" needs void *, and since printf is a variadic function, I need to cast the arguments to printf to void * in this case.

What does the above program print for you?

Edit: based upon the actual code posted for printing that you posted later: you are not getting the same value for &s1.b and &s1.b-1. You are getting the same value for &s1.b-1 and &s1. The answer to that is: this happens because of chance. In your case, there is struct padding, and sizeof(short)+sizeof(char) happens to be ≤ sizeof(int). If you were on a machine where any of those assumptions were invalid, you wouldn't see that behavior. I am sure if you changed char or short to int in your code, &s1.b-1 would not equal &s1, when printed.

Finally, you should cast pointers to void * before printing:

printf("%p %p \n",(void *)((&s1.b)-1), (void *)&s1);

Upvotes: 2

kusma
kusma

Reputation: 6678

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?

Upvotes: 1

Steve Jessop
Steve Jessop

Reputation: 279395

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

Upvotes: 6

Related Questions