Hi folks,
I have the following structure
typedef struct{
uint16_t PADDING;
uint16_t MOST_SBits;
uint16_t MED_SBits;
uint16_t LESS_SBits;
} foo_timer;
and relative global instance:
foo_timer foo_instance;
I wrote this macro:
#define FOOMACRO() ((foo_timer)(((uint64_t)foo_instance)+200))
and used it in my main:
int main(){
return FOOMACRO().LESS_SBits;
}
Compiling gives me this error:
*error: aggregate value used where an integer was expected*
The conversion to 64bits is to allow overflow handling.
Paragraph 6.5.4-2 requires both the type and the operand of the cast
operator to have a scalar type. foo_instance has type foo_timer which
is an aggregate type. The inner cast expression violates a constraint
of the language. foo_timer is still an aggregate type so the outer
cast expression violates the same constraint.
Even if the cast could work, unless foo_instance just happens to be
properly aligned for a uint64_t your code would invoke undefined
behavior.
You could get around both problems by using a union
typedef union {
uint64_t ALL_SBits;
foo_timer foo_instance;
} foo_union;
foo_union foo_aggregate;
You would then assign values to the four members of
foo_aggregate.foo_instance, do your arithmetic on
foo_aggregate.ALL_SBits, and return the value in
foo_aggregate.foo_instance.LESS_SBits. But this is a non-portable
solution.
You obviously want the treat the four 16-bit members as a single
64-bit value to force the overflow from LESS_SBits to increment
MED_SBits. This will only work if your machine is big-endian with
8-bit bytes and your structure has no padding. Consider a typical x86
little-endian machine where the four members of your structure have
the values 0, 100, 200, 65520. In hex, your structure would look like
0000 6400 c800 f0ff
Adding 200 to this 64-bit LITTLE-ENDIAN value produces
c800 6400 c800 f0ff
Thus, your four members end up with 200, 100, 200, 65520 instead of
the intended 0, 100, 201, 184.
The real solution to your problem is to compute the 64-bit value using
the << shift operator, which works on values and not representation
and is therefore insensitive to endianness
value64u = (foo_instance.MOST_SBits << 32) +
foo_instance.MED_SBits << 16) +
foo_instance.LESS_SBits;
You can then perform all the arithmetic you want on this value and
extract the desired set of bits using the >> operator, taking
advantage of the automatic modulo processing for unsigned integers.
foo_instance.MOST_SBits = value64u >> 32;
foo_instance.MED_SBits = value64u >> 16;
foo_instance.LESS_SBits = value64u;