Thursday, October 23, 2014

accessing structure member's address

points:

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:

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)
// Microsoft x86 compiler (version 7)
#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))

Explanation:
  1. ((s *)0) takes the integer zero and casts it as a pointer to s.
  2. ((s *)0)->m dereferences that pointer to point to structure member m.
  3. &(((s *)0)->m) computes the address of m.
  4. (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 &fsizeof(int)*sizeof(foo_t) gets added.
You can use offsetof operator if you want to do the math yourself, like this
int 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.


No comments:

Post a Comment