A macro with a ## will concatenate the two elements together, for example if you use #define sptember oct ## ober you will obtain october.
So my problem is:
I have a macro like this #define getRegByPin(pin) set ## pin than I have from 1 to 19 some defines like this: #define set0 xxx and #define set1 xxx, etc.
But when I call my macro in code
int p = getPinNo(pin); st(getRegByPin(p), p, to); it replaces getRegByPin(p) with setp instead of set0 or set13 or etc.
What can i do?
Thx for help! You are awesome! :)
The C preprocessor (and C++ has just inherited it), just does textual substitution. It knows nothing of variables. So given
#define getRegByPin(pin) set ## pin
const int p = 5;
getRegByPin(p); // Will expand to setp, not set5
From the syntax, I guess that set0 to set13 are constants. Do they have values you can calculate? For example:
auto getRegByPin(int pin) { return set0+pin; } // or (set0 << pin)
If not, you are going to need a constant array which you can index:
auto getRegByPin(int pin) {
static const setType_t pins[16] = { set0, set1, set2 ... set15};
return pins[pin];
}
If they are not constants, but functions, your array will need to be an array of function pointers.
Prefer to use functions than the preprocessor.
Related
I am using the X macro pattern to keep a bunch of arrays/items in sync, and I want to create an argument list from it, however I can't work out a way to get a well formed list. Here's what I mean:
#define MY_DATA \
X(var_one, e_one, 1) \
X(var_two, e_two, 2) \
X(var_three, e_three, 3) \
#define X(a,b,c) b,
enum MyNumbers {
MY_DATA
};
#undef X
#define X(a,b,c) c,
int MyValues[] = {
MY_DATA
};
#undef X
void my_func(int a, int b, int c) {} // example do-nothing proc
void main(void)
{
int var_one = MyValues[e_one];
int var_two = MyValues[e_two];
int var_three = MyValues[e_three];
#define X(a,b,c) a,
my_func(MY_DATA); // this fails because of the trailing comma
#undef X
}
Macros are not really my forte, so I can't think of a way of getting rid of the final comma in the function call. Can anyone think of a way to stop it?
Look at the Boost Preprocessor library for “preprocessor metaprogramming tools including repetition and recursion.”
Even if you don't use their complete package, the chapter I linked to explains some techniques, specifically including iteration to build data structures and statements.
Here's an idea: write
my_func(MY_DATA 0);
and declare my_func to take an extra (ignored) argument.
void my_func(int a, int b, int c, int)
I use a variant of this pattern frequently. However, it is normally used to define mappings between data. Along the lines of this:
MESSAGE(10, "Some error message"),
MESSAGE(11, "Som other error message"),
What des not make sense in your approach is that typically these constructs are used for large numbers of entries (100s, 1000s). You normally do not want that many arguments to a function.
If you really want to follow the approach, you could add another MACRO
#define MY_DATA \
X(var_one, e_one, 1) COMMA \
X(var_two, e_two, 2) COMMA \
X(var_three, e_three, 3) \
and define comma as needed when you define X. (Or you could just put the comma in directly).
Here is an option:
void my_func(int a, int b, int c, int dummy) {}
// ...
my_func(MY_DATA 0);
If you can't change my_func then make a thunk (i.e. an intermediate function that calls my_func)
A second option would be to include the comma in the MY_DATA macro instead of in X:
#define MY_DATA \
X(var_one, e_one, 1), \
X(var_two, e_two, 2), \
X(var_three, e_three, 3)
This has been bugging me for some time, I came across this while solving some objective type questions in C.
#define SWAP(a,b,c) c t;t=a;a=b;b=t;
int main() {
int x=10,y=20;
SWAP(x,y,int);
}
The code gives the correct answer:
Working code
In C are we supposed to pass just a data type as an argument.This supposedly works here but I want to know how.Also two more questions related to this:
If I want to swap using pointers, will it work
Will this work if SWAP is defined as a function instead of a macro.
Macros are pre-processed before compilation and you can virtually write anything in macros that would be replaced. In function arguments, you can not pass data types as arguments.
Side note:
#define SWAP(a,b,c) do { c t;t=a;a=b;b=t; } while(0)
is a safer macro implementation than the one mentioned by you. Moreover name t is quite common. If either of the argument name is t, this won't work as expected, so better choose some rare name. Capital letters are usually preferred in macro definition.
for ex: #define SWAP(a,b,c) do { c MACRO_TEMP_;MACRO_TEMP_=a;a=b;b=MACRO_TEMP_; } while(0)
SWAP(x,y,int); Becomes c t;t=a;a=b;b=t; where all occurances of c are replaced with int, a with x and b with y. Resulting in: ìnt t; t = x; x = y; y = t;
To understand the macros better, you can see the pre-processed output of your code. Output on my computer:
$ cat q26727935.c
#define SWAP(a,b,c) c t;t=a;a=b;b=t;
int main() {
int x=10,y=20;
SWAP(x,y,int);
}
$ gcc -E q26727935.c
# 1 "q26727935.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "q26727935.c"
int main() {
int x=10,y=20;
int t;t=x;x=y;y=t;;
}
$
Macro is replacement at pre-processor stage, so swap will work even with pointers, although this is superfluous.
In function you can not pass data type as arguments, so it won't work.
Yes.
No.
First of all, you have to know that when you are using macros, the argument will be replaced as they are. So, if you call SWAP(a, b, int*), it will be replace with
int* t;t=a;a=b;b=t;
and then the code will be compiled.
But when you're using functions, that won't happen and you're unable to pass data type as an argument to a function.
In an embedded system define:
#define Row1_PORT GPIOD
#define Row1_PIN GPIO_PIN_4
#define Row2_PORT GPIOD
#define Row2_PIN GPIO_PIN_7
#define Row3_PORT GPIOD
#define Row3_PIN GPIO_PIN_1
#define Row4_PORT GPIOD
#define Row4_PIN GPIO_PIN_3
//------------
#define Paste2(a,b) a ## b
#define Paste(a,b) Paste2(a,b)
#define NRows 4
I want use above defined macros in a loop like this:
for(i=1;i<=NRows;i++)
{
GPIO_Init(Paste(Paste(Row,i),_PORT),Paste(Paste(Row,i),_PIN),GPIO_MODE_IN_PU_NO_IT);
}
instead of
GPIO_Init(Row1_PORT,Row1_PIN);
GPIO_Init(Row2_PORT,Row2_PIN);
GPIO_Init(Row3_PORT,Row3_PIN);
GPIO_Init(Row4_PORT,Row4_PIN);
Is it possible?
I need some things like __COUNTER__ in ANSI C or C++. My compiler is IAR.
The preprocessor runs at compile time and textually modifies the source code presented to the compiler. What you are seeking to do is not possible; the compiler would embed the letter i into the macro expansions, not the value of the variable i at run-time.
I would probably use something like:
static const int ports[] = { 0, Row1_PORT, Row2_PORT, Row3_PORT, Row4_PORT };
static const int pins[] = { 0, Row1_PIN, Row2_PIN, Row3_PIN, Row4_PIN };
for (int i = 1; i <= NRows; i++)
GPIO_Init(ports[i], pins[i]);
Or I'd write it out longhand (as you show in your 'instead of' option) — there is little penalty and possibly a small saving for just 4 entries. If you have 100 ports to initialize, the loop would be better, of course.
Also, if you're going to use the port and pin numbers again in future (in other portions of the code than just the initialization code), having the arrays available will allow for greater flexibility.
As chris said -- this information isn't available to you during preprocessing, so you're ending up with
GPIO_Init(Rowi_PORT,Rowi_PIN);
which errors, as expected.
I don't think that macros are the right tool for this. Why not save your ports and pins in an array? Something like:
int ports[] = {Row1_PORT, Row2_PORT, ...};
int pins[] = {Row1_PIN, Row2_PIN, ...};
for (int i = 0; i < NRows; i++) {
GPIO_Init(ports[i], pins[i];
}
No less concise, but no macro hacks.
I want to append an integer variable to a function name using a macro but the following code doesn't work:
#define TEST(num) test_##num()
void test_0(void){ /* some code here*/ }
void somefunc(){
int somevar = 0;
TEST(somevar);
}
This ends up in a call to test_somevar().
I know that you can make an enum of numbers and use that list but i don't want to do this cause it kind of defeats the purpose of what i'm trying to do.
Is there a way to do this efficiently?
Run time values can't be used/seen by the preprocessor, but you can use an array of functions to do this:
int main(int argc, char *argv[]) {
void (*test[1])(void) = { test_0 };
test[0]();
return 0;
}
Or, given the array, you can define a macro:
#define TEST(x) test[x]()
This cannot work unless somevar is also a macro.
The reason is because TEST(somevar) is expanded into TEST_somevar at preprocessing time (assuming your macro works correctly), while the value of some_var is not known until (at least) compile time, if not run time.
Another way to do what you want to do is to have an array of function pointers and then have somevar index different tests within that array.
Let's say that I need to create a LUT containing precomputed bit count values (count of 1 bits in a number) for 0...255 values:
int CB_LUT[256] = {0, 1, 1, 2, ... 7, 8};
If I don't want to use hard-coded values, I can use nice template solution How to count the number of set bits in a 32-bit integer?
template <int BITS>
int CountBits(int val)
{
return (val & 0x1) + CountBits<BITS-1>(val >> 1);
}
template<>
int CountBits<1>(int val)
{
return val & 0x1;
}
int CB_LUT[256] = {CountBits<8>(0), CountBits<8>(1) ... CountBits<8>(255)};
This array is computed completely at compile time. Is there any way to avoid a long list, and generate such array using some kind of templates or even macros (sorry!), something like:
Generate(CB_LUT, 0, 255); // array declaration
...
cout << CB_LUT[255]; // should print 8
Notes. This question is not about counting 1 bits in an number, it is used just as example. I want to generate such array completely in the code, without using external code generators. Array must be generated at compile time.
Edit.
To overcome compiler limits, I found the following solution, based on
Bartek Banachewicz` code:
#define MACRO(z,n,text) CountBits<8>(n)
int CB_LUT[] = {
BOOST_PP_ENUM(128, MACRO, _)
};
#undef MACRO
#define MACRO(z,n,text) CountBits<8>(n+128)
int CB_LUT2[] = {
BOOST_PP_ENUM(128, MACRO, _)
};
#undef MACRO
for(int i = 0; i < 256; ++i) // use only CB_LUT
{
cout << CB_LUT[i] << endl;
}
I know that this is possibly UB...
It would be fairly easy with macros using (recently re-discovered by me for my code) Boost.Preprocessor - I am not sure if it falls under "without using external code generators".
PP_ENUM version
Thanks to #TemplateRex for BOOST_PP_ENUM, as I said, I am not very experienced at PP yet :)
#include <boost/preprocessor/repetition/enum.hpp>
// with ENUM we don't need a comma at the end
#define MACRO(z,n,text) CountBits<8>(n)
int CB_LUT[256] = {
BOOST_PP_ENUM(256, MACRO, _)
};
#undef MACRO
The main difference with PP_ENUM is that it automatically adds the comma after each element and strips the last one.
PP_REPEAT version
#include <boost/preprocessor/repetition/repeat.hpp>
#define MACRO(z,n,data) CountBits<8>(n),
int CB_LUT[256] = {
BOOST_PP_REPEAT(256, MACRO, _)
};
#undef MACRO
Remarks
It's actually very straightforward and easy to use, though it's up to you to decide if you will accept macros. I've personally struggled a lot with Boost.MPL and template techniques, to find PP solutions easy to read, short and powerful, especially for enumerations like those. Additional important advantage of PP over TMP is the compilation time.
As for the comma at the end, all reasonable compilers should support it, but in case yours doesn't, simply change the number of repetitions to 255 and add last case by hand.
You might also want to rename MACRO to something meaningful to avoid possible redefinitions.
I like to do it like this:
#define MYLIB_PP_COUNT_BITS(z, i, data) \
CountBits< 8 >(i)
int CB_LUT[] = {
BOOST_PP_ENUM(256, MYLIB_PP_COUNT_BITS, ~)
};
#undef MYLIB_PP_COUNT_BITS
The difference with BOOST_PP_REPEAT is that BOOST_PP_ENUM generates a comma-separated sequence of values, so no need to worry about comma's and last-case behavior.
Furthermore, it is recommended to make your macros really loud and obnoixous by using a NAMESPACE_PP_FUNCTION naming scheme.
a small configuration thing is to omit the [256] in favor of [] in the array size so that you can more easily modify it later.
Finally, I would recommend making your CountBit function template constexpr so that you also can initialize const arrays.