How about a more general solution based on typeof and sizeof?
#define pgm_read(v) ((typeof(*v)) \
(__builtin_choose_expr(sizeof(*v) == 1, pgm_read_byte(v), \
__builtin_choose_expr(sizeof(*v) == 2, pgm_read_word(v), \
__builtin_choose_expr(sizeof(*v) == 4, pgm_read_dword(v), \
({ char error[((sizeof(*v) == 1) || (sizeof(*v) == 2) || \
(sizeof(*v) == 4)) ? 1 : -1]; error[0]; }) \
)))))
The macro above looks a bit ugly, but it's not too hard to follow.
Basically, we are using sizeof(*v) to figure out the size of the data
you are wanting, and using it to pick the correct pgm_read_xxx function
for the data size. We use __builtin_choose_expr instead of ?: to avoid
any unwanted expression evaluations or side effects, as well as to allow
different sized return values. The "char error[...]" part is a way to
force a compile-time error if the macro is used with something whose
size is not 1, 2 or 4 bytes.
The result is that you can write:
char x;
char* PROGMEM FlashPointer = &x;
char* FlashPtr = pgm_read(&FlashPointer);
You can equally write:
static const PROGMEM uint8_t x8 = 8;
static const PROGMEM uint16_t x16 = 16;
static const PROGMEM uint32_t x32 = 32;
void test(void) {
volatile uint8_t y8 = pgm_read(&x8);
volatile uint16_t y16 = pgm_read(&x16);
volatile uint32_t y32 = pgm_read(&x32);
}
Now your pgm_read's are independent of the type, assuming they have a
compatible size.
Personally, my preference would be to change the semantics to remove the
"&", so that you would write:
char* FlashPtr = pgm_read(FlashPointer);
This is just a small change to the macro, but I think it's neater - you
are reading an object from flash, rather than reading data from an
address in flash. But such a change would require a name change to avoid
accidents.
mvh.,
David
_______________________________________________
AVR-libc-dev mailing list
address@hidden
http://lists.nongnu.org/mailman/listinfo/avr-libc-dev