points:
a. operators . and -> having higher precedence than & operator
b. to get the address of the structure member from pointer variable
a. operators . and -> having higher precedence than & operator
Operator
| Description |
Associativity
|
---|---|---|
. -> | Member selection via object name Member selection via pointer |
left-to-right
|
b. to get the address of the structure member from pointer variable
I have a
struct str *s
;
Let
var
be a variable in s
. Is &s->var
equal to &(s->var)
?
&s-> var == &(s->var)
Answer:
Behavior-wise, yes they are equivalent since the member access
->
operator has a higher precedence than the address-of &
operator.
Readibility-wise, the second one
&(s->var)
is much more readable than &s->var
and should be preferred over the first form. With the second form, &(s->var)
, you won't have to second-guess what it's actually doing as you know the expression in the parentheses are always evaluated first. When in doubt, use parentheses.
c. to get the address of the strucutre member from the normal variable:
struct measure {
char category;
int width;
int height;
};
// declare and populate the struct
struct measure ball;
ball.category = 'C';
ball.width = 5;
ball.height = 3;
// print the addresses of the struct and its members
printf("address of ball = %p\n", (void *)(&ball));
printf("address of ball.category = %p\n", (void *)(&ball.category));
printf("address of ball.width = %p\n", (void *)(&ball.width));
printf("address of ball.height = %p\n", (void *)(&ball.height));
// print the size of the struct
printf("sizeof(ball) = %lu\n", sizeof(ball));
4. working of offset macro / getting offset of the particular structure member:
// Keil 8051 compiler
#define offsetof(s,m) (size_t)&(((s *)0)->m)
#define offsetof(s,m) (size_t)&(((s *)0)->m)
// Microsoft x86 compiler (version 7)
#define offsetof(s,m) (size_t)(unsigned long)&(((s *)0)->m)
#define offsetof(s,m) (size_t)(unsigned long)&(((s *)0)->m)
// Diab Coldfire compiler
#define offsetof(s,memb) ((size_t)((char *)&((s *)0)->memb-(char *)0))
#define offsetof(s,memb) ((size_t)((char *)&((s *)0)->memb-(char *)0))
Explanation:
- ((s *)0) takes the integer zero and casts it as a pointer to s.
- ((s *)0)->m dereferences that pointer to point to structure member m.
- &(((s *)0)->m) computes the address of m.
- (size_t)&(((s *)0)->m) casts the result to an appropriate data type.
By definition, the structure itself resides at address 0. It follows that the address of the field pointed to (Step 3 above) must be the offset, in bytes, from the start of the structure. At this point, we can make several observations:
5. question:
Consider a struct with two members of integer type. I want to get both members by address. I can successfully get the first, but I'm getting wrong value with the second. I believe that is garbage value. Here's my code:
#include <stdio.h>
typedef struct { int a; int b; } foo_t;
int main(int argc, char **argv)
{
foo_t f;
f.a = 2;
f.b = 4;
int a = ((int)(*(int*) &f));
int b = ((int)(*(((int*)(&f + sizeof(int))))));
printf("%d ..%d\n", a, b);
return 0;
}
I'm getting:
2 ..1
Can someone explain where I've gone wrong?
Answer:
The offset of the first member must always be zero by the C standard; that's why your first cast works. The offset of the second member, however, may not necessarily be equal to the size of the first member of the structure because of padding.
Moreover, adding a number to a pointer does not add the number of bytes to the address: instead, the size of the thing being pointed to is added. So when you add
sizeof(int)
to &f
, sizeof(int)*sizeof(foo_t)
gets added.
You can use
offsetof
operator if you want to do the math yourself, like thisint b = *((int*)(((char*)&f)+offsetof(foo_t, b)));
The reason this works is that
sizeof(char)
is always one, as required by the C standard.
Of course you can use
&f.b
to avoid doing the math manually.
Reference:
No comments:
Post a Comment