c - Why does avr-gcc tell me about missing argument while expanding my [fancy] macro? -


i'm developing code atmel, defines consistent register names program port pins. instance:

  • portc traditionally used set (high or low) pin on port c
  • pinc used read state of particular pin on port c
  • ddrc used read/write direction (0=input, 1=output) of pin on port c

so found code — understand — defines pin macro this:

#define led_pin    c,7 

then following macros (restricted use case i'm talking here):

#define _bv(bit)                        (1 << bit) ... #define _set(type, name, bit)           type ## name |= _bv(bit) #define _clear(type, name, bit)         type ## name &= ~ _bv(bit) #define _test(type, name, bit)          ( type ## name  & _bv(bit) ) ... #define output(pin)         _set(ddr, pin) #define input(pin)          _clear(ddr, pin) ... #define high(pin)           _set(port, pin) #define low(pin)            _clear(port, pin) 

so can write function main() follows:

main() {   output(led_pin);   high(led_pin); } 

while convenient , prevents defining 3 macros (e.g. pinc7, portc7 , ddrc7) 1 led, main concern is imposes redefine avr macros account kind of notation, bearing in mind avr macros use sfr registers arguments (from sfr_defs.h):

#define bit_is_set(sfr, bit) (_sfr_byte(sfr) & _bv(bit)) 

also, avr defines macros convert [what i'd call] bare registry names actual memory-mapped special-function register names (sfr) avr-gcc:

#define _sfr_byte(sfr) _mmio_byte(_sfr_addr(sfr)) 

and _sfr_addr() adds offset 0 or 20 according target atmel cpu. in order enhance compatibility avr library functions, take sfr register plus optional argument, decided rewrite initial code , tried following:

#define _sfr_bit(type, name, bit)   type ## name, bit #define _port(pin)                  _sfr_bit(port, pin) #define _pin(pin)                   _sfr_bit(pin, pin) #define _ddr(pin)                   _sfr_bit(ddr, pin)  #define set_bit(sfr, bit)           _sfr_byte(sfr) |= _bv(bit) #define set_output(pin)             set_bit(_pin(pin)) 

but face compiler error message write in function main():

set_output(led_pin); 

main.cpp:72:19: error: macro "set_bit" requires 2 arguments, 1 given

i same error if try this, too:

#define set_output(pin)             set_bit(_sfr_bit(ddr, pin)) 

why macro output(), passes two out of of three arguments _set() compiles fine , macro doesn't?


as jens gustedt pointed to, generic explanation lies in order of compiler resolves macros.

to transform arbitrary number of arguments passed function fixed number of arguments using macro, function name can made argument macro:

#define expand(f, ...)              f(__va_args__) #define _sfr_bit(type, name, bit)   type ## name, bit ... #define set_bit(sfr, bit)           _sfr_byte(sfr) |= _bv(bit) ... #define set_output(pin)             expand(set_bit, _sfr_bit(pin, pin)) 

how many , arguments passed function (first argument) resolved without "argument missing" compiler error.

a refined version:

#define _sfr_x(f, type, name, bit)  f(type ## name, bit) ... #define set_bit(sfr, bit)           _sfr_byte(sfr) |= _bv(bit) ... #define set_output(pin)             _sfr_x(set_bit, pin, pin) 

disclaimer

the code not yet in production. code may ugly, of course. it's base work under construction. hence not yet finalized.

the decomposition of arguments set_bit several takes place before _sfr_bit macro expandend. when sees comma resulted expansion of latter, late.

a common trick expand argument once more

#define set_bit0(...)   set_bit(__va_args__) #define set_output(pin) set_bit0(_pin(pin)) 

here _pin(pin) expanded , passt set_bit0. when passing arguments set_bit0 set_bit sees expandend sequence, including comma.


Comments

Popular posts from this blog

Spring Boot + JPA + Hibernate: Unable to locate persister -

go - Golang: panic: runtime error: invalid memory address or nil pointer dereference using bufio.Scanner -

c - double free or corruption (fasttop) -