iterating through a struct in c

2019-06-05 07:57发布

问题:

I am writing a Unit Test that is similar to this code, and I am trying to test my values as I set them, so that I know what is going on. I don't understand why the ptr values are not being set to 1, when I run the following code. Instead when I run this it gives me an output of 10, 64, 0, 0.

Any explanation or advise would be greatly appreciated!

#include <stdio.h>
#include <stdbool.h>

typedef struct
{
    bool bOne;
    bool bTwo;
    bool bThree;
    bool bFour;
} items;

int main()
{
    items item;
    item.bOne = 0;
    bool *ptr = &(item.bOne);

    for(int i = 0; i < sizeof(items)/sizeof(bool); i++)
    {
        *ptr = 1;
        *ptr++;
        printf("ptr value = %d\n", *ptr);
    }
    return 0;
}

回答1:

In *ptr++, the ++ has higher precedence than the *, so this post-increments the pointer, and reads and discards the value originally pointed to. Now that the pointer has been incremented, you are reading uninitialized memory in the printf. If your intention was to increment the value being pointed at, try:

(*ptr)++;

Or

ptr[0]++;

Edit

Hmm, since your loop bound is based upon the number of bools that fit in the size of the struct, maybe your intention was to increment the pointer. In which case, you don't need to dereference it at the same time, and you shouldn't expect to get anything meaningful in the printf. Also, as pointed out, since the struct is not an array, you will be wandering into undefined behavior land since the compiler may decide to add padding:

From C99 §6.7.2.1:

12 Each non-bit-field member of a structure or union object is aligned in an implementation- defined manner appropriate to its type.

13 Within a structure object, the non-bit-field members and the units in which bit-fields reside have addresses that increase in the order in which they are declared. A pointer to a structure object, suitably converted, points to its initial member (or if that member is a bit-field, then to the unit in which it resides), and vice versa. There may be unnamed padding within a structure object, but not at its beginning.



回答2:

You have two major problems.

First, you have a logical error in that you advance your pointer before printing out the value it points to; instead of printing the value of the thing you just set, you're printing the value of the next uninitialized member. You need to reverse the order of the advance and print statements like so:

printf("ptr value = %d\n", *ptr);
ptr++; // note no * operator

Or just combine the operation in one expression:

printf("ptr value = %d\n", *ptr++);

This assumes that you can use %d to print a bool value - I'm not sure about that offhand (may have to explicitly cast the argument to (int)).

But you have a bigger problem - it's not guaranteed that you can iterate through the members of a struct type with a pointer like this. Even though all the members are the same type, it's not guaranteed that there won't be padding between members (it depends on the size of the bool type and the alignment requirements of your platform).

Your code may work as intended, or it may lead to corrupted data within your struct instance, or any number of other issues. The safer thing to do is use a separate array of pointers to those members, since it is guaranteed that you can iterate through an array with a pointer:

bool *members[] = { &item.bOne, &item.bTwo, &item.bThree, &item.bFour, NULL };

bool *ptr = members[0];
while ( ptr )
{
  *ptr++ = 1;
}

If you still want output, you'd write

*ptr = 1;
printf( "ptr value = %d\n", *ptr++ );

You could get creative and combine the assignment and pointer advance within the print statement:

printf( "ptr value = %d\n", (*ptr++ = 1) );

but that would probably get you hit.