C token substitution - preventing macro substitution at certain points - c

I am attempting to make a section of code a bit more generic for a microcontroller that I am currently programming for.
What I want is a specific macro, formed from other tokens via concatenation. The problem is that one of the tokens is defined as a specific memory address (i.e. a register) and thus "garbage" is substituted mid-way. The following snippet illustrates the problem:
#include <stdio.h>
#include <stdint.h>
// The actual final token that I want (because I want the value of 10)
#define I_DRINK_BEER 10
// This line is the problematic line!
// It us defined in the microcontroller-specific header
// If this line is not defined, it works perfectly as desired.
#define DRINK (*(uint32_t*) (0x8000))
#define ACTION DRINK
#define INDIRECT(who,action,what) who ## action ## what
#define TOKEN_PASTE(who,action,what) INDIRECT(who,action,what)
#define CONSUMPTION(who,what) TOKEN_PASTE(who,ACTION,what)
int main(void)
{
printf("Value = %d\n", CONSUMPTION(I_,_BEER));
return 0;
}
If the line "#define DRINK ..." is commented out, the program compiles and executes as desired:
damien#damien-desktop:~$ gcc -o test test_macro_expansion.c
damien#damien-desktop:~$ ./test
Value = 10
But the inclusion of the offending line substitutes the complete address that makes the pre-processor complain:
test_macro_expansion.c: In function ‘main’:
test_macro_expansion.c:21:1: error: pasting "I_" and "(" does not give a valid preprocessing token
test_macro_expansion.c:21:1: error: pasting ")" and "_BEER" does not give a valid preprocessing token
test_macro_expansion.c:21:28: error: expected ‘)’ before ‘_BEER’
Is there a way I can tell the pre-processor not to substitute a particular token any further?
Why??
Before this seems a little esoteric, I have a timer for some particular functionality that is assigned to timer/counter "TCC0" in one project and "TCD1" in another project. It happens to be defined in as the base address of the register block for each timer, respectively. So, I have in my config header:
#define PERIPHERAL_TIMER TCC0
Which, works well in the main, because the registers of the timer can be referenced easily, for example:
value = PERIPHERAL_TIMER.CCA;
Deep in the toolchain, TCC0 is defined:
#define TCC0 (*(TC0_t *) 0x0800) /* Timer/Counter C0 */
The problem is that I have other macros defined in that have the TCC0) as part of the the name that I need elsewhere, for example:
// Note the TCC0 in the function argument!
EventSystem_SetEventSource(EVSYS_CHMUX_TCC0_OVF_gc);
Hence, I would like to define the symbol
// Conceptually what I want!
#define EVENT_SOURCE(timer) EVSYS_CHMUX_ ## timer ## _OVF_gc
// The "PERIPHERAL_TIMER" gets expanded to the address, not the token that I want
#define PERIPHERAL_EVENT EVENT_SOURCE(PERIPHERAL_TIMER)
I hope this clears up why I am asking the question.

#define DRINK (*(uint32_t) (0x8000)). this line has an error which is as UNDEFINED Symbol uint .

Well, the simplest, easiest workaround that solves this particular issue is:
// It was this...
// #define PERIPHERAL_TIMER TCC0
// And is now this
#define PERIPHERAL_TIMER_SUFFIX C0
So the macros can be easily defined:
// Conceptually what I want - modified, but be sure to use
// indirect substitution as required.
#define EVENT_SOURCE(timer) EVSYS_CHMUX_TC ## timer ## _OVF_gc
And PERIPHERAL_TIMER can still be defined for direct register access:
// Don't forget, you'll need to use indirect substitution
#define PERIPHERAL_TIMER TC ## PERIPHERAL_TIMER_SUFFIX
// Registers can still be access as:
value = PERIPHERAL_TIMER.CCA;
NOTE: Indirect substitution in this post refers to the technique in this answer.

Related

Unusual syntax for a #define directive

In a sketch I found the following instruction:
#define USB_CONFIG_POWER_MA(mA) ((mA)/2)
And I want to be sure not to make any mistake: why are there two "mA"?
Which one should I replace by a value given that in a previous version of this code one just needed this line:
#define USB_CONFIG_POWER_MA(20)
to set the max to 20mA but now it gives a compilation error:
/home/henry/arduino-1.8.16/hardware/arduino/avr/cores/arduino/USBCore.h:99:29: error: "20" may not appear in macro parameter list
This seems to be the solution as it gives me no compilation error
#define USB_CONFIG_POWER_MA(mA) ((40)/2)
but again i want to be sure!
With
#define USB_CONFIG_POWER_MA(mA) ((mA)/2)
you define a function-like macro, where mA is the argument to the macro.
You can use it like:
printf("USB power for 20 mA is %d\n", USB_CONFIG_POWER_MA(20));
The preprocessor will replace the macro as such:
printf("USB power for 20 mA is %d\n", ((20)/2));
If you always want the macro to be replaced by the value 20 then either define a function-like macro where you ignore the argument (this will be backward compatible):
#define USB_CONFIG_POWER_MA(mA) 20
Or define a macro without arguments (this will require you to change all macro invocations):
#define USB_CONFIG_POWER_MA 20
The latter, without arguments, is often used in C as a way to define symbolic constants, and as such makes more sense in your use-case.
Another possible solution is to use the original macro definition, but use a second macro to define the value to pass as argument:
#define USB_CONFIG_POWER_MA(mA) ((mA)/2)
#define USB_CONFIG_DEFAULT_POWER 40
// ...
printf("USB power for 20 mA is %d\n",
USB_CONFIG_POWER_MA(USB_CONFIG_DEFAULT_POWER));
This will both be backward compatible and allow other values to be used together with the original USB_CONFIG_POWER_MA macro.
to set the max to 20mA
You shouldn't change the definition of the USB_CONFIG_POWER_MA macro, you should change the value that's passed to it where it's used. The macro you're talking about comes from USBCore.h:
#define D_CONFIG(_totalLength,_interfaces) \
{ 9, 2, _totalLength,_interfaces, 1, 0, \
USB_CONFIG_BUS_POWERED | USB_CONFIG_REMOTE_WAKEUP, \
USB_CONFIG_POWER_MA(USB_CONFIG_POWER) }
You can see the macro being used to set the configured power here. Looking deeper, the definition of USB_CONFIG_POWER is:
#ifndef USB_CONFIG_POWER
#define USB_CONFIG_POWER (500)
#endif
So USB_CONFIG_POWER only gets defined if it isn't already defined. That means that all you need to do to set the power that your Arduino sketch requests is to make sure that you define USB_CONFIG_POWER yourself before you include the USBCore.h file. Put a line like:
#define USB_CONFIG_POWER (20)
in your code before you include that file, and you should be good to go.

Macro constants concatenation using ##

I'm writing some libraries for a microcontroller, and for that purpose, I use macro-like functions. For example, a macro-like function to enable an I2C module is defined as:
#define I2C_MODULE_ENABLE(_x) \
I2C##_x##CONLbits.I2CEN = 1
where _x is the module number (e.g.,1 or 2 in my case).
If a user calls this macro-like function as I2C_MODULE_ENABLE(1), it would be expanded by a preprocessor as I2C1CONLbits. I2CEN = 1.
However, if a user calls this macro-like function as I2C_MODULE_ENABLE(MY_I2C), where MY_I2C is a macro constant defined in a user-defined config.h file that is included by my i2c.h library (e.g., the macro constant is defined as #define MY_I2C 1), the macro-like function would be expanded as I2CMY_I2CCONLbits. I2CEN = 1.
I know that I need to somehow evaluate the MY_I2C macro constant before concatenation, and I can do that by adding another macro level:
#define __I2CxCONLbits(_x) I2C##_x##CONLbits
#define I2C_MODULE_ENABLE(_x) \
__I2CxCONLbits.I2CEN = 1
My question is: is there a more elegant solution to this problem since I have multiple registers like the CONLbits register. Using this approach I would need to define a special __I2CxREGISTER(_x) macro for every register.
I tried to do something like this:
#define __I2Cx(_x) I2C##_x
#define I2C_MODULE_ENABLE(_x) \
__I2Cx(_x)##CONLbits.I2CEN = 1
but that produces an output like this: I2C1 CONLbits .I2CEN = 1, and my compiler is complaining about the whitespace between I2C1 and CONLbits tokens.
You aren't adding the macro level properly, as I see it. The usual idiom is to define a wrapper that does nothing but forward the argument. That way, if the argument is itself a macro, it will be expanded before being passed to the macro that is wrapped:
#define I2C_MODULE_ENABLE__(x_) \
I2C##x_##CONLbits.I2CEN = 1
#define I2C_MODULE_ENABLE(x_) \
I2C_MODULE_ENABLE__(x_)
I took the liberty of renaming your macro parameter, since identifiers with leading underscores are defined as reserved for the implementation, I think it's better to be safe than sorry.
To solve your problem of the space I'd go with the proverbial level of indirection, and use a function like macro to generate the correct prefix token, and pass it along two levels to make sure it's expanded correctly:
#define I2Cx__(x_) I2C##x_
#define I2C_MODULE_ENABLE__(IC_) \
IC_##CONLbits.I2CEN = 1
#define I2C_MODULE_ENABLE_(IC_) \
I2C_MODULE_ENABLE__(IC_)
#define I2C_MODULE_ENABLE(x_) \
I2C_MODULE_ENABLE_(I2Cx__(x_))
See it live here
The whole shtick is to make sure the preprocessor sees and produces valid tokens at each step. Which can be a bit tiresome.

Check for concatenated define in C preprocessor

I access registers by concatenated defines unsing the function GETREG
#define NUMBER 1 //changes
#define REG1 register.N1
#define REG2 register.N2
#define REG8 register.N8
#define GETREG_(N) REG ## N
#define GETREG(N) GETREG_(N)
Sometimes the registers for that NUMBER are not defined so i want to make sure the macro correctly expands before inserting it in the code so i tried to do:
#define NUMBER 5
#ifdef GETREG(NUMBER)
GETREG(NUMBER) = 0
#endif
However this always seems to evaluate as true and the compiler prints
Warning:extra tokens at end of #ifdef directive
Background Story:
In my projects I create libraries to interface with a HAL to abstract the hardware level. Often from one project to another the codebasis in the HAL stays exactly the same but just the location of pins changes. For that reason i would like to use macro-expansion to access the pins. The following macro does the job for me at adressing the analog features of the pin:
#define ANSEL_(Pin) _ANS ## Pin
#define ANSEL(...) ANSEL_(__VA_ARGS__)
that way i can turn on or off analog features by:
#define PIN_RX A0
ANSEL(PIN_RX)= 0;
and other registers by similar macros. The problem i am facing now is that some pins for example do not have analog features (e.g. Pin A5). Because of that i would like to test if the define in the library esists. I was tryin to do this by:
#ifdef ANSEL(PIN_RX)
ANSEL(PIN_RX)= 0;
#endif
However this simple approach is not working.
The microcontroller (PIC33) lib:
Edit: Shipped from the manufactorer
#define ANSELA ANSELA
extern volatile unsigned int ANSELA __attribute__((__sfr__));
typedef struct tagANSELABITS {
unsigned ANSA0:1;
unsigned ANSA1:1;
unsigned ANSA2:1;
unsigned ANSA3:1;
unsigned ANSA4:1;
unsigned :4;
unsigned ANSA9:1;
} ANSELABITS;
extern volatile ANSELABITS ANSELAbits __attribute__((__sfr__));
/* ANSELA */
#define _ANSA0 ANSELAbits.ANSA0
#define _ANSA1 ANSELAbits.ANSA1
#define _ANSA2 ANSELAbits.ANSA2
#define _ANSA3 ANSELAbits.ANSA3
#define _ANSA4 ANSELAbits.ANSA4
#define _ANSA9 ANSELAbits.ANSA9
You have the wrong expectation for the behavior of the #ifdef directive. That directive is equivalent to #if defined, where defined is a preprocessing operator in that context. Although the condition of an overall #if directive is evaluated only after the line is fully macro-expanded, the defined operator operates on the next preprocessing token, which must have the form of an identifier, before macro expansion:
Prior to evaluation, macro invocations in the list of preprocessing tokens that will become the controlling constant expression are replaced (except for those macro names modified by the defined unary operator) [...]
[C2011, 6.10.1/4]
Thus, your
#ifdef GETREG(NUMBER)
tests whether GETREG is a defined macro, and the (NUMBER) constitutes a sequence of unexpected extra tokens.
The defined operator therefore cannot serve your purpose. It is conceivable that there is a way to use a more general #if directive to achieve your aim, but I'm not seeing it at the moment. Instead, I'm inclined to suggest letting the compiler find such errors for you, instead of expecting the preprocessor to do it. If compile time is too late, then perhaps you need to look to a build configuration system such as the Autotools or CMake could help you create.
You can do more or less what you want if you are prepared to use two #defines instead of one for each pin:
#define HAS_ANS_A0 1
#define ANS_A0 ANSELAbits.ANSA0
#define HAS_ANS_A1 1
#define ANS_A1 ANSELAbits.ANSA1
#define HAS_ANS_A5 1
#define ANS_A5 ANSELAbits.ANSA5
#define HAS_ANSEL_(Pin) HAS_ANS_ ## Pin
#define HAS_ANSEL(...) HAS_ANSEL_(__VA_ARGS__)
#define ANSEL_(Pin) ANS_ ## Pin
#define ANSEL(...) ANSEL_(__VA_ARGS__)
#if HAS_ANSEL(PIN_RX)
ANSEL(PIN_RX)= 0;
#endif
This works because in an #if, an undefined identifier token (that is, an identifier token which has not been #defined) has the value 0. It is not an error, or even a warning.
Note: I changed the symbols starting _ANS to conform with §7.1.3 (Reserved Names), paragraph 1:
All identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use.

Preprocessor directives in C : macros using __LINE__

I find it difficult to understand the working of a macro defined with the help of preprocessor directives.
The macro,
TRXEM_SPI_BEGIN()
is defined with the help of two preprocessor directives refereed from two header files. Firstly, I wish to state the declaration of the said macro.
#define TRXEM_SPI_BEGIN() st( TRXEM_PORT_OUT &= ~TRXEM_SPI_SC_N_PIN; NOP();)
As the declaration of macro st () is missing here, I found it defined in a different header file and ti is shown below.
#define st(x) do { x } while (__LINE__ == -1)
Now after combining two macros, the true definition of macro TRXEM_SPI_BEGIN() must be,
#define TRXEM_SPI_BEGIN() do {
( TRXEM_PORT_OUT &= ~TRXEM_SPI_SC_N_PIN; NOP(); )
} while (__LINE__ == -1)
This code is written to work inside a microcontroler where TRXEM_PORT_OUT, RXEM_SPI_SC_N_PIN are memory mapped registers and NOP initiates an instruction cycle that does nothing.
As per my understanding, __LINE__ means the line of code in the c file where __LINE__ lies. That line can never be equal to -1. i.e. this loopmust always be running only once provided the __LINE__ can never be placed in -1 place in a .c file. Simply put, -1 can never be the value of __LINE__.
Therefore, I believe a do while() loop here is unnecessary and the same output could have been achieved by simply without using any looping.
I do not understand the functioning of this macro. I would so much appreciate if someone could elaborate on it.
As per my understanding, means the line of code in the c file
where __LINE__ lies. That line can never be equal to -1. i.e. this
loopmust always be running only once provided the __LINE__ can never
be placed in -1 place in a .c file. Simply put, -1 can never be the
return value to a __LINE__.
Your understanding is exactly correct here. It is there to make sure the code runs exactly once.
Think of following scenario:
#define BAZ foo();bar();
Now if you do
if(some_cond) BAZ;
This is equivalent to:
if(some_cond) foo();
bar();
Which is most possibly not something you want. So you change it to:
#define BAZ {foo();bar();}
This works fine if written as if(some_cond) foo() else wow(); but would fail compilation if written as if(some_cond) foo(); else wow();
So you define BAZ as
/* No semicolon at end */
#define BAZ do {foo();bar();} while(condition_which_is_always_false)
And you can now write the natural code with intuitive semicolon at end.
In your case, condition_which_is_always_false is __LINE__ == -1

Are #include directives processed prior to macro expansion regardless of their location within a file?

I came across some code the other day that was similar to the following (the following has been over-simplified for the sake of brevity):
config.h
#ifndef __CONFIG__
#define __CONFIG__
#define DEVELOPMENT_BLD _TRUE_
#if (DEVELOPMENT_BLD == _TRUE_)
#define FILE_EXT ".dev"
#else
#define FILE_EXT ".bin"
#endif
#define PROJECT_STRING "my_project"
#define FILE_NAME PROJECT_STRING FILE_EXT
/* Common include files */
#include "my_defs.h"
#endif /* __CONFIG__ */
my_defs.h
#ifndef __MY_DEFS__
#define __MY_DEFS__
#define _TRUE_ 1
#endif /* __MY_DEFS__ */
The project had always compiled without any issues, but since I made some minor changes (and the actual project was rather large) I decided to run Lint on it. When I did, I received the following error:
Warning 553: Undefined preprocessor variable '_TRUE_', assumed 0
I then wondered why the compiler didn't catch that _TRUE_ is defined in my_defs.h which is included after the macro's first usage. So I compiled it on a different compiler with the same results - succesful compilation, no warnings and FILE_NAME was correctly evaluated regardless of how I set DEVELOPMENT_BLD (using _TRUE_ or !_TRUE_). Here are my two compiler settings:
ArmCC -c -cpu Cortex-M3 -g -O0 --apcs=interwork -I "..\ARM\CMSIS\Include" -I "..\ARM\INC\NXP\LPC17xx" -o "file.o" --omf_browse "file.crf" --depend "file.d" "file.c"
mingw32-gcc.exe -pedantic -Wall -g -c D:\dev\practice\header_question\main.c -o obj\Debug\main.o
I decided to run a simple test to see if the value of FILE_NAME was being properly evaluated by the preprocessor. I also wanted to see what the value of DEVELOPMENT_BLD actually was. I ran the following code two times:
main.c
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("FILE_NAME:%s, WHAT_IS_TRUE:%d", FILE_NAME,DEVELOPMENT_BLD);
return 0;
}
The first time I used the value #define DEVELOPMENT_BLD _TRUE_ with this result:
FILE_NAME:my_project.dev, WHAT_IS_TRUE:1
The second time I used the value #define DEVELOPMENT_BLD !_TRUE_ with this result:
FILE_NAME:my_project.bin, WHAT_IS_TRUE:0
My first thought was that perhaps _TRUE_ was being defined elsewhere - so just to be sure I commented out #include "my_defs.h". I then began to receive a compiler error:
error: '_TRUE_' undeclared (first use in this function)
All of that leads to my question. Are #include statements required to be evaluated by the preprocessor before macro expansion or did I just get lucky?
The C pre-processor acts on directives as it encounters them. In this context, the warning is correct; at the time you use #if DEVELOPMENT_BUILD == _TRUE_, the effective value of _TRUE_ is zero. However, because of the #define DEVELOPMENT_BUILD _TRUE_ definition, the preprocessor is evaluating #if 0 == 0, which is true. However, you'd have had the same result if you'd specified #define DEVELOPMENT_BUILD _FALSE_ because _FALSE_ would also be implicitly 0 and hence the test would be #if 0 == 0 again (which also evaluates to true). If, when the preprocessor has finished evaluating expressions in the #if condition, there are identifiers left over, they are implicitly assumed to be 0.
Note that names starting with an underscore and a capital letter or another underscore are reserved for any use by the implementation. You are treading on very thin ice with your choice of names such as _TRUE_ and __CONFIG__. (Just because system headers use names like that is not a good reason for you to do so — in fact, quite the opposite. The system headers are carefully keeping out of the namespace reserved for you to use; you should keep out of the namespace reserved for the system.)

Resources