Use #define to specify multiple paramaters [duplicate] - c

I want to be able to define a tuple which represents the arguments needed by other macros.
I think the best way to show what I want is to show an example:
#include <avr/io.h>
#define LED_PORT PORTB
#define LED_DDR DDRB
#define LED_PIN PB7
#define LED LED_PORT, LED_DDR, LED_PIN
#define OUTPUT(port, ddr, pin) ddr |= 1 << pin
void main(void) {
OUTPUT(LED);
}
I want OUTPUT(LED) to be then expanded into:
LED_DDR |= 1 << LED_PIN
The problem that I get is to do with the order of expansion, and results in the following error:
macro "OUTPUT" requires 3 arguments, but only 1 given
This is for use with an AVR project with custom built hardware where I have defined LED and other components with a respective LED_PORT LED_DDR and LED_PIN.
I then want to define more macros that can take this LED and use the appropriate arguments to map to the most succinct way possible.
Is this possible with the standard C-preprocessor?

You can add a level of indirection to the macro to achieve this:
#define OUTPUT_I(port, ddr, pin) ddr |= 1 << pin
#define OUTPUT(spec) OUTPUT_I(spec)
During rescanning, spec is expanded before OUTPUT_I, so the OUTPUT_I macro sees three parameters.

Related

How to define a macro of two tokens in Cpp

In my Arduinoc (cpp) code, I have these macros that set/clear bit y of register x:
#define SET(x,y) x |= (1 << y)
#define CLEAR(x,y) x &= ~(1<< y)
In several places I then use:
CLEAR(PORTB,7)
or
SET(PORTB,7)
I would like to define a macro to be PORTB,7 so it only appear once, in a header file, not all over my code. (I show only one example, but I have several conbinations of PORTx,N in my code).
I tried:
#define CLOCK PORTB,7
#define CLOCK_HIGH SET(CLOCK)
but it then fails to build with:
error: macro "SET" requires 2 arguments, but only 1 given CLOCK_HIGH; delay(DELAY); CLOCK_LOW; delay(DELAY);
Is there a way to achieve that?
You must first expand the macro inside. Ie. do another pass. Your code may look like this:
#define SET(x,y) do{ (x) |= (1u << (y)); }while(0)
#define CLEAR(x,y) do{ (x) &= ~(1u << (y)); }while(0)
#define HIGH(a) SET(a) // another empty pass, just forward
// the `a` is expanded and the second `SET` takes two arguments
// or better, but not fully compliant:
// #define HIGH(...) SET(__VA_ARGS__)
#define CLOCK PORTB, 7
#define CLOCK_HIGH() HIGH(CLOCK)
int main() {
int PORTB;
CLOCK_HIGH();
}
As a good measure research about macro pitfalls and research good practices when writing macros..

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

I'm developing code for Atmel, which defines consistent register names to program port pins. For instance:
PORTC is traditionally used to set (high or low) any pin on port C
PINC is used to read the state of a particular pin on port C
DDRC is used to read/write the direction (0=input, 1=output) of any pin on port C
So I found some code — which I fully understand — that defines a PIN macro like this:
#define LED_PIN C,7
Then the following macros (restricted to the use case I'm talking about 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 I can write a function main() as follows:
main() {
OUTPUT(LED_PIN);
HIGH(LED_PIN);
}
While it is very convenient and prevents from defining three macros (e.g. PINC7, PORTC7 and DDRC7) for just one LED, my main concern about this is that is imposes to also redefine AVR macros to account for that kind of notation, bearing in mind AVR macros use SFR registers as arguments (from sfr_defs.h):
#define bit_is_set(sfr, bit) (_SFR_BYTE(sfr) & _BV(bit))
Also, AVR defines macros to convert from [what I'd call] bare registry names to actual memory-mapped special-function register names (sfr) for avr-gcc:
#define _SFR_BYTE(sfr) _MMIO_BYTE(_SFR_ADDR(sfr))
and _SFR_ADDR() adds an offset 0 or 20 according to the target Atmel CPU. So in order to enhance compatibility with those AVR library functions, which take an SFR register plus an optional argument, I decided to rewrite the initial code and tried the 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 then I face a compiler error message as soon as I write something like this in function main():
set_output(LED_PIN);
main.cpp:72:19: error: macro "set_bit" requires 2 arguments, but only 1 given
I get the same error if I try this, too:
#define set_output(pin) set_bit(_SFR_BIT(DDR, pin))
Why is that macro OUTPUT(), which passes only two out of of three arguments to _SET() compiles fine and my macro doesn't?
As Jens Gustedt pointed to, the generic explanation lies in the order of which the compiler resolves macros.
To transform an arbitrary number of arguments to be passed to a function with a fixed number of arguments using a macro, the function name can be made an argument to the 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 and which arguments are passed to the function (first argument) is resolved without any "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 is not yet in production. The code may be ugly, of course. It's mostly some base work under construction. Hence not yet finalized.
The decomposition of the arguments for set_bit into several takes place before the _SFR_BIT macro is expandend. So when it then sees the comma that resulted from the expansion of the latter, it is already too late.
A common trick is to expand the argument once more
#define set_bit0(...) set_bit(__VA_ARGS__)
#define set_output(pin) set_bit0(_PIN(pin))
Here _PIN(pin) is expanded and passt to set_bit0. When passing the arguments from set_bit0 to set_bit it sees the already expandend sequence, including the comma.

#define a tuple in C

I want to be able to define a tuple which represents the arguments needed by other macros.
I think the best way to show what I want is to show an example:
#include <avr/io.h>
#define LED_PORT PORTB
#define LED_DDR DDRB
#define LED_PIN PB7
#define LED LED_PORT, LED_DDR, LED_PIN
#define OUTPUT(port, ddr, pin) ddr |= 1 << pin
void main(void) {
OUTPUT(LED);
}
I want OUTPUT(LED) to be then expanded into:
LED_DDR |= 1 << LED_PIN
The problem that I get is to do with the order of expansion, and results in the following error:
macro "OUTPUT" requires 3 arguments, but only 1 given
This is for use with an AVR project with custom built hardware where I have defined LED and other components with a respective LED_PORT LED_DDR and LED_PIN.
I then want to define more macros that can take this LED and use the appropriate arguments to map to the most succinct way possible.
Is this possible with the standard C-preprocessor?
You can add a level of indirection to the macro to achieve this:
#define OUTPUT_I(port, ddr, pin) ddr |= 1 << pin
#define OUTPUT(spec) OUTPUT_I(spec)
During rescanning, spec is expanded before OUTPUT_I, so the OUTPUT_I macro sees three parameters.

AVR clean pin aliasing solution - enumerating I/O bits

I'm working in C on an Arduino device, where the pins are labeled differently. I'm using PLAIN C though, not the Arduino "language".
Each pin is defined by it's port (eg. PORTB) and pin (bit) in the port (eg. PB0).
I'd like to concisely alias pins, so I could make macros or functions somewhat like what the Arduino uses:
pin_direction(D2, 1); // D2 as output
set_pin(D2, 0); // write zero to D2
pin_direction(D3, 0); // D3 as input
enable_pullup(D3, 1); // enable D3 pullup
Instead (atm) I have to use something ugly like this:
#define D0 0
#define D1 1
#define D2 2
#define D3 3
...
#define D10 2
#define D11 3
#define PORT_D0 PORTD
#define PORT_D1 PORTD
#define PORT_D2 PORTD
#define PORT_D3 PORTD
...
#define PORT_D10 PORTB
#define PORT_D11 PORTB
// the same for PIN_xx and DDR_xx
And then I can use macros to do the work:
#define sbi(port, bit) (port) |= _BV(bit)
#define cbi(port, bit) (port) &= ~ _BV(bit)
sbi(DDR_D2, D2); // D2 to output
cbi(PORT_D2, D2); // D2 to output
sbi(DDR_D3, D3); // D3 as input
sbi(PORT_D3, D3); // D3 pullup enable
Now this works, but it's very messy. Any idea how to - without a monster overhead of something like huge switch - do this better - more like my first example? Somehow enumerate all bits and then resolve the right register on the fly?
I'm using avr-gcc with avr-libc.
You can define macros which expand to multiple tokens, e.g.
#define PIN_D0 PORTD, 0
#define PIN_D1 PORTD, 1
...
#define PIN_D10 PORTB, 2
Then use them in macros such as:
sbi(PIN_D0); // expands to sbi(PORTD, 0)
Some utility macros that may be useful with these macros are:
#define PORT_OF(port, bit) port
#define BIT_OF(port, bit) bit
which can be used in contexts such as:
PORT_OF(PIN_D10) // expands to PORTB
BIT_OF(PIN_D10) // expands to 2
Here's the solution I use.
In my util.h (common to all my AVR projects):
#define DDR_REG(port) DDR ## port
#define PORT_REG(port) PORT ## port
#define PIN_REG(port) PIN ## port
#define SET_BIT(port, bit) do { (port) |= (1 << (bit)); } while(0)
#define CLR_BIT(port, bit) do { (port) &= ~(1 << (bit)); } while(0)
#define BIT_IS_SET(port, bit) ((((uint8_t)(port)) >> ((uint8_t)(bit))) & 0x1)
#define IO_SET_INPUT_AUX(port, bit) CLR_BIT(DDR_REG(port), bit)
#define IO_SET_AS_INPUT(io) IO_SET_INPUT_AUX(io)
#define IO_SET_OUTPUT_AUX(port, bit) SET_BIT(DDR_REG(port), bit)
#define IO_SET_AS_OUTPUT(io) IO_SET_OUTPUT_AUX(io)
#define IO_OUTPUT_0_AUX(port, bit) CLR_BIT(PORT_REG(port), bit)
#define IO_OUTPUT_0(io) IO_OUTPUT_0_AUX(io)
#define IO_OUTPUT_1_AUX(port, bit) SET_BIT(PORT_REG(port), bit)
#define IO_OUTPUT_1(io) IO_OUTPUT_1_AUX(io)
#define IO_GET_INPUT_AUX(port, bit) BIT_IS_SET(PIN_REG(port), bit)
#define IO_GET_INPUT(io) IO_GET_INPUT_AUX(io)
In my pin mappings file:
#define UPBTN_IO B,7
#define DOWNBTN_IO D,0
#define ENTERBTN_IO D,1
(etc)
In code:
IO_SET_AS_INPUT(UPBTN_IO);
This relies on some fun preprocessor bits, like there only being one round of macro expansion on macro parameters.

How to return definition argument

I have this definition
#define LED_CLOCK_PIN (DDRD, PORTD, PD6)
I want to write two more definitions, in order to get PORTD and PD6 values, something like this
#define GET_PORT(_PORT_) /*some magic goes here*/
#define GET_PIN(_PIN_) /*some magic goes here*/
uint8_t port = GET_PORT(LED_CLOCK_PIN);
uint8_t pin = GET_PIN(LED_CLOCK_PIN);
Is it possible?
Do you mean something like:
#define LED_CLOCK_PIN (DDRD, PORTD, PD6)
#define SND(A, B, C) B
#define GET_PORT(X) SND X
uint8_t port = GET_PORT(LED_CLOCK_PIN);
gcc -E processes it to uint8_t port = PORTD;. I'm not sure if this is fully portable and guaranteed by standard.
If you were permitted to change you first define to:
#define LED_CLOCK_PIN DDRD, PORTD, PD6
then with C99 you can do (not tested):
#define GET_PORT(x) (((int[]){x})[1])
Is there a reason you would want to parameterize the port instead of accessing it directly by name? That is, instead of
#define GET_PORT
Would it make more sense to have something like
#define GET_PORT_D (port.D)
#define LED_CLOCK_PIN 0x10 //Bit 5 of the port.D register, for example
#define GET_LED_CLOCK_PIN ( (port.D & LED_CLOCK_PIN) >> 4)
This way, there is no ambiguity to what you're doing with the port, so it improves readability. Second, the likelihood that you are changing what LED_CLOCK_PIN actually means (since it accesses hardware) is probably pretty low, so again why not make the code unambiguous.

Resources