I would like to write a function which returns a pointer to either one of two special function registers (SFRs). These SFRs have different types, but their types are identical except for their names:
#define SFRxType SFR0Type
typedef struct SFR0Type {
union {
struct {
uint16_t var0;
uint16_t var1;
};
struct {
uint32_t var;
};
};
} SFR0Type;
extern volatile SFR0Type SFR0 __attribute__((__sfr__));
typedef struct SFR1Type {
union {
struct {
uint16_t var0;
uint16_t var1;
};
struct {
uint32_t var;
};
};
} SFR1Type;
extern volatile SFR1Type SFR1 __attribute__((__sfr__));
(The __sfr__
attribute tells the compiler the variable address is set by the linker script.)
These typedefs reside in a header I do not own, so I cannot change them.
My function looks like this:
static volatile SFRxType* get_sfr_ptr(uint16_t select) {
return select ? &SFR1 : &SFR0;
}
However, this produces a compiler warning: warning: pointer type mismatch in conditional expression
.
How can I write a function like this without generating a warning, given the above constraints?
The
?:
isn't really suitable since it requires the 2nd and 3rd operands to be of types that are either compatible or can be made compatible by implicit conversion. If using that operator you have to cast the operand which isn't of the correct type and from there dive down into this "language lawyer" rabbit hole (C17 6.5.15):Unfortunately these 2 structs here are not compatible because someone had the bad idea to use different struct tags for them. If not for those otherwise 100% superfluous tags, they would have been compatible even if
typedef
names were different.So the best option is probably to forget all about implicit conversions and composite types and instead use
if
. Keep it simple. And do explicit casts no matter which type that's picked:But please note that this returned pointer will still have to get cast to its correct type before use - again because the structs are not compatible.