FelipeCosta
FelipeCosta

Reputation: 56

Can't understand why I got these results using struct offset in C

I was playing with structs and trying to get their values using offsets, this is my code

#include <stdio.h>
#include <stddef.h>

typedef struct abcd{
    int a,b;
    double c,d;
}abcd;

int main()
{
    abcd teste = {.a = 3, .b = 5, .c = 7, .d = 9};
    printf("value of a: %d  //value of b:  %d\n",*( (char*) &teste), *((char*) &teste + offsetof(abcd, b)) );
    return 0;
}

output: value of a: 3 //value of b: 5

everything works fine but when I change the printf to

printf("value of a: %d  value of b: %d\n", *( &teste), *((char*) &teste + offsetof(abcd, b)) );
//No casting to (char*) in value of a

I get the output: value of a: 5 value of b: 1360854088

Why does this happens?

Upvotes: 1

Views: 102

Answers (2)

Liyuan Liu
Liyuan Liu

Reputation: 172

printf %d but you pass sturct adcd, this is a undefined action, result is undefined,it should consider printf.c implement.

my code:

 typedef struct abcd{
        int a,b;
            double c,d;
}abcd;

int main()
{
    abcd teste = {.a = 3, .b = 5, .c = 7, .d = 9}; 
    printf("value of a: %d  //value of b:  %d\n",*( (char*) &teste), *((char*) &teste + offsetof(abcd, b)) );
    printf("%d\n", offsetof(abcd, b));
    printf("value of a: %p  value of b: %p\n", ( &teste), ((char*) &teste + offsetof(abcd, b)) );
    printf("value of a: %d  value of b: %d\n", teste, *((char*) &teste));
    printf("value of a: %p  value of b: %p\n", &teste, ((char*) &teste));
    printf("value of a: %d  value of b: %d\n", teste, *((char*) &teste));
    //No casting to (char*) in value of a
    return 0;
}
result:
value of a: 3  //value of b:  5
4
value of a: 0x7fff86f203b0  value of b: 0x7fff86f203b4
value of a: 3  value of b: -2114388464
value of a: 0x7fff86f203b0  value of b: 0x7fff86f203b0
value of a: 3  value of b: -2114388464

undfined process cause unkonwn result

Upvotes: 0

Peter Cordes
Peter Cordes

Reputation: 365950

printf("value of a: %d  value of b: %d\n", *( &teste), *((char*) &teste + offsetof(abcd, b)) );

This passes teste by value, which takes more space than a single int. The 2nd %d will probably be getting input from some of the bytes of the first arg. Compiler warnings make this clear:

$ clang-3.5 -Wall  bad-printf.c -O3 
bad-printf.c:12:48: warning: format specifies type 'int' but the argument has type 'abcd' (aka 'struct abcd') [-Wformat]
    printf("value of a: %d  value of b: %d\n", *( &teste), *((char*) &teste + offsetof(abcd, b)) );
                        ~~                     ^~~~~~~~~~

$ gcc -Wall  bad-printf.c -O3 
bad-printf.c: In function ‘main’:
bad-printf.c:12:5: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘abcd’ [-Wformat=]
     printf("value of a: %d  value of b: %d\n", *( &teste), *((char*) &teste + offsetof(abcd, b)) );
     ^

$ ./a.out 
value of a: 5  value of b: 0

$ uname -a
Linux tesla 3.19.0-22-generic #22-Ubuntu SMP Tue Jun 16 17:15:15 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux

It also passes a one-byte character to printf, as the 3rd arg (2nd arg after the format string). The other bytes in the register (or on the stack, if you compiled for obsolete 32bit x86) may be leftover from something else.

Check the assembly output. You'll probably find a one-byte load from &abcd.b, leaving the other bytes untouched.

You've told printf (by using %d) that you passed it a full int. If you only wanted to print an 8bit integer (so it wouldn't treat the padding as data), you need a size prefix to your format specifier.

Upvotes: 2

Related Questions