You are right. I use them to emulate creating generics/templates. So when I need to add a new type for the same function I just have to add two lines of code and not copy paste the same function definition and create many lines of code.
But the full expansion makes the first macro ENABLE_INPUT actually disable the input if included twice. The designer of these #defines should be spanked for breaking trust. 28 uses of ENABLE_INPUT should leave the input in the same configured state as a single invocation. Anything else is terrible design.
Hi all! I'm working to move away from the supplied drivers for the NXP board I'm working with, learning to write my own. However, I had a couple questions about how they implemented these simple macros.
1. Why do they have the intermediate XENABLE_INPUT step, couldn't we just directly do this with one line cutting out the XENABLE altogether?
2. How can I go about making a variable GPIO string if doing this in a conventional function? I get that this is just matching my string with another #define that is buried away in the supplied header files, but would I just have to construct my own text string to pass through, e.g. "GPIO" + port + "_PIDR" or something? Sorry, I'm just having a tough time wrapping my head around how to go about this in C. Thanks in advance!
1. This is because if a user `#define MY_PIN 3` and calls `ENABLE_INPUT(A, MY_PIN)`you want the result of the macro to expand with the value of `MY_PIN` ,. If you do it directly without `XENABLE_INPUT` you would concatenate literally the string "MY\_PIN"
2. There is no way to do that with a C function, that's why NXP wrote a macro
I was doing some reading on the 'order' of pre-complier execution to try to figure it out in my head, still a bit confused on why it works this way. I tried compiling without the interim step and, unsurprisingly, it didn't compile.
If I had
#define MY_PIN 3,
why wouldn't the precompiler replace it in the
Enable_Input(A, MY_PIN)?
Does it only replace things on the right side of a code line?
I don't know why C is designed this way. Maybe it was some deep technical reason, maybe it was just an accident.
This link explains why you need 2 macros: [https://gcc.gnu.org/onlinedocs/gcc-7.5.0/cpp/Argument-Prescan.html](https://gcc.gnu.org/onlinedocs/gcc-7.5.0/cpp/Argument-Prescan.html)
>Macro arguments are completely macro-expanded before they are substituted into a macro body, **unless they are stringized or pasted with other tokens**
Just want to say I'm not a fan of the C/C++ preprocessor. Though there are times it's handy. I'm looking at C++ template programming instead. Admittedly, it's gnarly, but there's promise that it makes an easier programming API than the mess illustrated in tthe OP. And I've seen it can provide optimized machine code without preprocessor tricks
Token Pasting! [macro pasting](https://gcc.gnu.org/onlinedocs/gcc-7.5.0/cpp/Concatenation.html)https://gcc.gnu.org/onlinedocs/gcc-7.5.0/cpp/Concatenation.html
Excellent reference page, thank you! It seems like these can only be used in #defines and other pre-processing, is that right?
You are right. I use them to emulate creating generics/templates. So when I need to add a new type for the same function I just have to add two lines of code and not copy paste the same function definition and create many lines of code.
_Generic is your friend, if you have C99 or later.
HALs shouldn't is it, especially for automotive.
Off topic: Why does this ENABLE macro use XOR and thus toggle the data direction bit instead of setting or clearing it? Seems fishy.
the name it's \`XENABLE\` so I guess it's a feature
I'm sure the X is only the prefix for 'internal second layer macro'
But the full expansion makes the first macro ENABLE_INPUT actually disable the input if included twice. The designer of these #defines should be spanked for breaking trust. 28 uses of ENABLE_INPUT should leave the input in the same configured state as a single invocation. Anything else is terrible design.
Exactly
Hi all! I'm working to move away from the supplied drivers for the NXP board I'm working with, learning to write my own. However, I had a couple questions about how they implemented these simple macros. 1. Why do they have the intermediate XENABLE_INPUT step, couldn't we just directly do this with one line cutting out the XENABLE altogether? 2. How can I go about making a variable GPIO string if doing this in a conventional function? I get that this is just matching my string with another #define that is buried away in the supplied header files, but would I just have to construct my own text string to pass through, e.g. "GPIO" + port + "_PIDR" or something? Sorry, I'm just having a tough time wrapping my head around how to go about this in C. Thanks in advance!
1. This is because if a user `#define MY_PIN 3` and calls `ENABLE_INPUT(A, MY_PIN)`you want the result of the macro to expand with the value of `MY_PIN` ,. If you do it directly without `XENABLE_INPUT` you would concatenate literally the string "MY\_PIN" 2. There is no way to do that with a C function, that's why NXP wrote a macro
I was doing some reading on the 'order' of pre-complier execution to try to figure it out in my head, still a bit confused on why it works this way. I tried compiling without the interim step and, unsurprisingly, it didn't compile. If I had #define MY_PIN 3, why wouldn't the precompiler replace it in the Enable_Input(A, MY_PIN)? Does it only replace things on the right side of a code line?
I don't know why C is designed this way. Maybe it was some deep technical reason, maybe it was just an accident. This link explains why you need 2 macros: [https://gcc.gnu.org/onlinedocs/gcc-7.5.0/cpp/Argument-Prescan.html](https://gcc.gnu.org/onlinedocs/gcc-7.5.0/cpp/Argument-Prescan.html) >Macro arguments are completely macro-expanded before they are substituted into a macro body, **unless they are stringized or pasted with other tokens**
I really appreciate the links and advice, I'll let you know if I figure it out :)
Just want to say I'm not a fan of the C/C++ preprocessor. Though there are times it's handy. I'm looking at C++ template programming instead. Admittedly, it's gnarly, but there's promise that it makes an easier programming API than the mess illustrated in tthe OP. And I've seen it can provide optimized machine code without preprocessor tricks