1

I am managing an array of 4 flags of uint8_t each.

uint8_t flags[4].

these flags can change by different threads at any moment.

i want to be able to get a snapshot of these flags by using one atomic operation. lets say i do the following :

uint32_t temp_val = read_atomic32((uint32_t *) &flags[0])

now i cast back to an array of flags:

uint8_t *my_flags = &temp_val;
printf("flag zero is %d\n, my_flags[0]);

i am suspecting few problems here:

  1. maybe flags[4] is not aligned for uint32_t reads and might give a non-aligned crash or prehaps the atomic functionality will not be garunteed because of nonaligned access.

  2. what about endians? should a problem occur? even though i am using uint32_t i am later on casting it back to an array of uint8_t and i don't think the memory layout will be changed because of this action - still, maybe i am missing something here. i am assuming here that if i read a memory location for 4 bytes, these pattern will be the same until cast back no matter if your machine is little endian or big endian.

  3. is there a better way to manage 4 independent flags of uint8_t but still be able to read them as whole using one action in a portable safe way?

1 Answer 1

2

Place your flags in a union:

union {
  uint8_t  c[4];
  uint32_t t;
} flags;

flags.c[0] = ...;
flags.t = 0xffffffffU;

This takes care of the alignment issue and you can use the type punning to access the flags via t without a cast. Not quite kosher according to strict ISO C rules, but usually does what you want.

Endianness becomes an issue the moment you assign literal values (as in my example) or expect certain values when accessing flags.t. Just reading a value and then writing one just read (unmodified--no bit twiddling!) should be okay.

Sign up to request clarification or add additional context in comments.

7 Comments

thanks. so using a union will force the compiler to put this structure on an aligned address as the code can access t.
Exactly. The alignment requirement of a union is the maximum alignment requirement of all its members. Since all members must be at offset zero this guarantees that c is aligned just like t.
Type punning with unions works in most compilers for practical reasons. However I believe that by the standard a compiler is allowed to store flags.c and flags.t in different registers which would result in disconnected values.
@ZanLynx I don't believe so because the Standard guarantees that any object can be accessed as an array of unsigned char. And all three of flags, c and t must have the same address.
@Jens i didn't quite understand your comment about endianness. having flags.t used only for reading the array pattern and then simply assinging it to another flags2.t to be able to read flags2.c should be ok on all systems, do you agree ?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.