first of all: a "macro" is something very different than any C++-language detail
using the #define "statement" to make the compiler "write" code
#define can be used to make the compiler replace text that describes something with (almost) anything else
easy example
let's assume IO-pin number 4 shall be set to work as output
the command for defining an IO-pin to be configured as output is
pinMode(4,OUTPUT);
the number "4" says nothing about he purpose of this IO-pin
let's assume the IO-pin shall switch On/Off a buzzer
you would have to add a comment to explain
pinMode(4,OUTPUT); // IO-pin 4 is buzzer
the compiler needs the number. To make the code easier to read and understand
#define BuzzerPin 4
So the command looks like this
pinMode(BuzzerPin,OUTPUT);
the descriptive word "BuzzerPin" gets replaced through the compiler by a "4"
so what the compiler compiles is still 'pinMode(4,OUTPUT);'
This means - in some way - the define changes your source-code-file right before compiling
pinMode(BuzzerPin,OUTPUT);
gets replaced by
pinMode(4,OUTPUT);
the #define can do much more than just replace a word by a single number
it can even take parameters like in this example
#define dbg(myFixedText, variableName) \
Serial.print( F(#myFixedText " " #variableName"=") ); \
Serial.println(variableName);
// usage: dbg("1:my fixed text",myVariable);
// myVariable can be any variable or expression that is defined in scope
here myFixedText and variableName are "variables" on the macro-level
if you write this line
dbg("Hello",Counter);
and you start compiling there will happen two steps
inside the define
#define dbg(myFixedText, variableName)
Serial.print( F(#myFixedText " " #variableName"=") );
Serial.println(variableName);
the macro-variable myFixedText is "evaluated to "Hello"
the macro-variable variableName is evaluated to Counter
which means as a first step what happends is
#define dbg("Hello", Counter)
and a second step replace #define dbg("Hello", Counter) by
Serial.print( F("Hello" " " Counter"=") );
Serial.println(Counter);
It will be enough if you understand the pattern
writing
somewhere in your code you defined a variable
int Counter = 123;
somewhere else in your code you write
dbg("Hello",Counter);
results in serial output
"Hello" Counter=123
writing
somewhere in your code you defined a variable
char myArrayOfChar [ ] = "This is my message";
and somewhere else in your code
dbg("Test",myArrayOfChar);
results in serial output
"Test" myArrayOfChar=This is my message
writing
somewhere in your code you defined a variable
byte numberOfButtonPresses = 678;
and somewhere else in your code
dbg("function myTestfunc",numberOfButtonPresses);
results in serial output
"function myTestfunc" numberOfButtonPresses=678
So dbg and dbgi work this way
first parameter a fixed text that is just quoted
second parameter a variable-name or an expression where the macro prints to the serial monitor the variable-name a "=" and then the value of the variable
best regards Stefan