Reputation: 16345
I have a pointer to a structure and I'd like to fetch all of its members by trial and error. I'm trying to run through the structure by incrementing the pointer by one and derefencing it. It should return a correct value from the structure (every i*sizeof(int)
time) but it doesn't.
What am I doing wrong?
fn (mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)
{
/*
assume that all struct members are int types
typedef struct
{
mach_msg_bits_t msgh_bits;
mach_msg_size_t msgh_size;
mach_port_t msgh_remote_port;
mach_port_t msgh_local_port;
mach_msg_size_t msgh_reserved;
mach_msg_id_t msgh_id;
} mach_msg_header_t;
size of the struct is 24.
*/
printf("ID: %d \n",InHeadP->msgh_id); //prints 'ID: 1337'
printf("Ptr: %p\n",InHeadP);
for (int i = 0; i <= 24; i++)
{
int deref = *((int*)(InHeadP+i));
printf("InHeadP[%d]=%d\n",i,deref);
//no sign of 1337 anywhere
}
}
P.S. I know that I shouldn't be doing that, but this is only for testing purposes.
Upvotes: 1
Views: 10753
Reputation: 57728
A preferred method to iterate through a structure is to create a function that returns the value or address of the field given an index. Note that if the order of the members in the struct changes, this function must change too:
int * Index_Of(unsigned int index, mach_msg_header_t * p_struct)
{
switch (index)
{
case 0: return (int *) &(p_struct->msgh_bits);
case 1: return (int *) &(p_struct->msgh_size);
case 2: return (int *) &(p_struct->msgh_remote_port);
case 3: return (int *) &(p_struct->msgh_local_port);
case 4: return (int *) &(p_struct->msgh_reserved);
case 5: return (int *) &(p_struct->msgh_id);
}
return 0;
}
Just remember that treating the structure as contiguous fields (members) is not advisable since the compiler is allowed to add padding between structure members. Thus any method to access the fields except by name, is dangerous and will lead to very difficult bugs.
BTW, treating each field as an int
is also dangerous. If any of the types is changed to something else, like a double
, your code will break. Compiler will not catch the error because casting tells the compiler YOU know what you are doing.
You could "turn the picture around" and implement a Visitor pattern:
struct Visitor_Void
{
void (*fn_msgh_bits)(mach_msg_bits_t);
void (*fn_msgh_size)(mach_msg_size_t);
void (*fn_msgh_remote_port)(mach_port_t);
void (*fn_msgh_local_port)(mach_port_t);
void (*fn_msgh_reserved)(mach_msg_size_t);
void (*fn_msgh_id)(mach_msg_id_t);
};
void Visit_Members(mach_msg_header_t * p_header,
struct Visitor_Void * p_visitor)
{
(p_visitor->fn_msgh_bits)(p_header->msgh_bits);
(p_visitor->fn_msgh_size)(p_header->msgh_size);
(p_visitor->fn_msgh_remote_port)(p_header->msgh_remote_port);
(p_visitor->fn_msgh_local_port)(p_header->msgh_local_port);
(p_visitor->fn_msgh_reserved)(p_header->msgh_reserved);
(p_visitor->fn_msgh_id)(p_header->msgh_id);
return;
}
Upvotes: 3
Reputation: 5505
Wait a second, this is wrong:
int deref = *((int*)(InHeadP+i));
You want
int deref == *((int*)InHeadP+i)
You skipping 24 bytes each time through the loop, rather than 4.
Upvotes: 0
Reputation: 11699
When you call (int*)(InHeadP+i) you are doing pointer arithmetic on mach_msg_header_t which is size 24. So your first iteration is at the beginning of the struct, and your second iteration is right after your struct. You are accessing some other memory.
Try (((int*)InHeadP)+i).
Upvotes: 0
Reputation: 92321
No, you shouldn't be doing this!
What is particularly wrong here
for (int i = 0; i <= 24; i++)
{
int deref = *((int*)(InHeadP+i));
printf("InHeadP[%d]=%d\n",i,deref);
}
is that you print the first int of 24 different structs.
Upvotes: 1
Reputation: 57590
Because InHeadP
is a mach_msg_header_t*
, adding an integer to it will actually add that integer times sizeof(mach_msg_header_t)
, as though you were indexing an array of mach_msg_header_t
s (and is actually how array indexing works). You need to cast InHeadP
to an int*
before performing arithmetic on it, and even then, as the struct has six fields, i
should only go up to 6, not 24.
Upvotes: 5