krb
krb

Reputation: 16345

Run through a structure and print all the values?

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

Answers (5)

Thomas Matthews
Thomas Matthews

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

andrewdski
andrewdski

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

David V
David V

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

Bo Persson
Bo Persson

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

jwodder
jwodder

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_ts (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

Related Questions