I would like to make a macro F taking a variable number of parameters, that expands to the parameters each separated by a ||. e.g. F(a, b, c) should expand to a || b || c, F(a) should expand to just a, etc.
I know C doesn't support recursive macros. I only need this for at most 4 arguments currently.
I was thinking something like #define F(a, ...) a || F(__VA_ARGS__), and then a second macro to get that to expand 4 times, but I'm not sure at all what that other macro should look like. And I run into the issue of having an empty __VA_ARGS__ at some point. Any other ideas would be much appreciated.
Restrictions: must work with any standard-conforming C99 compiler.
EDIT: I've got this working using Overloading Macro on Number of Arguments, but still curious if there's another solution.
The basics are pretty easy:
#define COUNT(...) COUNT_(__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0)
#define COUNT_(A0, A1, A2, A3, A4, A5, A6, A7, ...) A7
#define F0()
#define F1(A0) A0
#define F2(A0, A1) A0 || A1
#define F3(A0, A1, A2) F2(A0, A1) || A2
#define F4(A0, A1, A2, A3) F3(A0, A1, A2) || A3
#define F(...) C(F, COUNT(__VA_ARGS__))(__VA_ARGS__)
#define C(X, Y) C_(X, Y)
#define C_(X, Y) X ## Y
where C is the usual two-step concatenation macro. There's one problem left, though: The empty __VA_ARGS__.
Actually, this is not supported by the C standard itself (you'd have to switch to upcoming C++20 for – or maybe C20 backports?). And the task is quite heavy (as is, COUNT() yields to 1, where the first argument in COUNT_ macro is an empty one!). I managed to solve this for a similar task quite a while ago, so you might want to have a look at there, should be easy enough to import the relevant part to here...
This is kinda heavy duty, but if you can use libraries, then Boost.PP can do much of the heavy lifting for you. It supports both C and C++, and is a header only library (obviously). Your use case will look like this:
#include <boost/preprocessor/variadic/to_seq.hpp>
#include <boost/preprocessor/seq/fold_left.hpp>
#define OP(s, state, x) state || x
#define F(...) BOOST_PP_SEQ_FOLD_LEFT(OP, 0, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))
The above converts the variadic arguments into a boost PP sequence, and then folds it by applying OP. state is the intermediate result of every "iteration". It's initial "value" is 0 (so that the resulting expression not depend on it).
And when running F(1, 2, 3) through gcc -E we get:
0 || 1 || 2 || 3
The major caveat with an empty argument list (a GCC extension formally, not valid C99), is that it will expand to 0 ||. So that is worth keeping in mind. Argument counting (with Boost.PP) may possibly be used to choose between one of two implementation depending on 0 or more args to get around the issue.
Related
I saw Macro expansion ignores some tokens in MSVC earlier, and was curious about the behaviour of the MSVC preprocessor. Obviously the correct answer to that and similar questions is "Don't use the MSVC preprocessor, use the newer, conforming one instead", but out of curiosity I tried to figure out what exactly is going on.
I tried playing around with the preprocessor on Godbolt, and my working theory is something like "If MSVC considers expanding a function-like macro inside an argument list to another function, and decides not to do the expansion, it replaces the argument list with the name of the function-like macro it decided not to expand".
Excusing the informal language above, this idea seems to hold pretty well for single-argument macros, as we see in the above Godbolt link, but doesn't seem to work too well for two-argument macros, which seem to be doing something a little differently.
Code I was playing around with included below:
#define S(s) s
#define Z(a, b) a b
#define F()
#define K() S(x S(F) x)
#define L() S(x S(F))
#define M() S(S(F) x)
#define N2() S(F) x
#define N() S(N2())
#define O() S(S(S) x)
#define P() S(S(A) x)
#define R() Z(Z(F,F) x, Z(Z,Z) y)
#define Q() Z(Z(Z,Z) x, Z(F,F) y)
K() // expands to 'F'
L() // expands to 'x F'
M() // expands to 'F'
N() // expands to 'F x'
O() // expands to 'S x'
P() // expands to 'A x'
R() // expands to 'F F'
Q() // expands to 'Z Z x F'
On GCC, we get the following (different) output:
x F x
x F
F x
F x
S x
A x
F F x Z Z y
Z Z x F F y
I've looked at the documentation for the MSVC preprocessor, and was not able to find an answer.
So, my question is, under what circumstances does the above behaviour (erasing some tokens from the argument list) happen, and which tokens will be erased?
Note: This question is not "the MSVC preprocessor is not doing what I want", but rather "the MSCV preprocessor behaves differently than the GCC one, I would like to know the rules it follows".
In C I have a define like:
#define VALUE 5
But the user can set a function too:
#define VALUE get_value()
For historical reasons
#define VALUE 0
means "the value is not set, use the default"
The question is how to write an #if that decides if VALUE is 0.
#if VALUE == 0
...
#else
...
#endif
gives "missing binary operator before token "("" error with GCC.
EDIT:
To make the use case clearer:
#if VALUE == 0
set_default_value();
#else
set_value(VALUE)
#endif
So I don't need VALUE to be evaluated in the #if just see if it's literally '0' or not.
You can use preprocessing pattern matching.
#define SECOND(...) SECOND_I(__VA_ARGS__,,)
#define SECOND_I(A,B,...) B
#define GLUE(A,B) GLUE_I(A, B)
#define GLUE_I(A,B) A##B
#define ZERO_TEST(X_) SECOND(GLUE(ZERO_TEST_AGAINST_,X_),0)
#define ZERO_TEST_AGAINST_0 ,1
The key construct here is the SECOND macro, which indirectly expands to its second argument. For pattern matching, you would use this by carefully constructing a first argument; since SECOND normally expands to its second argument, whatever you construct is normally ignored. But since SECOND expands to its second argument indirectly, you can cherry pick a particular pattern by having the first argument expand in particular cases with a comma, which would shove in a new second argument.
In this case we have an indirect paste at the end of ZERO_TEST_AGAINST_, and we're looking for the result of that to be ZERO_TEST_AGAINST_0.
To use this:
#if ZERO_TEST(VALUE)
set_default_value();
#else
set_value(VALUE)
#endif
Demo
http://coliru.stacked-crooked.com/a/2a6afc189637cfd3
Caveat
This fits your spec precisely as given; the indirect paste would not work with this form if you have parenthetical definitions:
#define VALUE (5)
...or:
#define VALUE (get_value() << 2) | 1
...since ZERO_TEST_AGAINST_ and ( do not join to make a valid token.
A generic solution is likely impossible, but you can hack something together:
#define CAT(x, ...) CAT_(x, __VA_ARGS__)
#define CAT_(x, ...) x##__VA_ARGS__
#define CHECK_VALUE_CHECK_0 )(
#define CHECK_VALUE_FALSE(...) CHECK_VALUE_TRUE
#define CHECK_VALUE_TRUE() 1
#define CHECK_VALUE CHECK_VALUE_(CAT(CHECK_VALUE_CHECK_, VALUE))
#define CHECK_VALUE_(...) CHECK_VALUE_FALSE(__VA_ARGS__)
#if CHECK_VALUE
#error Value is 0.
#else
#error Value is not 0.
#endif
Now, if VALUE is defined to 0, the macro CHECK_VALUE will expand to 1. Otherwise it will expand to CHECK_VALUE_TRUE, which as an unknown identifier, is considered falsey by #if.
This solution is hacky:
If VALUE starts with 0,, its causes a hard error.
If VALUE starts with something other than a letter or digit or _ (e.g. (), it causes a hard error.
...
A preprocessor cannot evaluate C-Functions, such as get_value(). It can only handle static data, as its replaced with code prior to compilation, so your statements are not executed at runtime.
if (VALUE == 0) in your C-Code would get replaced for example with if (get_value() == 0) prior to compilation. The Preprocessor is not able to evaluate the return value of get_value() (even if it would always return 0).
A #define VALUE 5 line makes the C preprocessor replace the string VALUE with the string 5 wherever it sees it (outside "strings", that is). The resulting program will not even contain VALUE anymore, and that is what the compiler proper sees(1).
Do an experiment: Get your program (cut it down to a few lines), and run:
cc -E proggie.c > proggie.i
Under Unixy systems you'll get a file proggie.i that contains preprocessed C, which is what the compiler proper sees. No VALUE in sight, and trying to set VALUE in the source ends up as trying to set 0, which obviously won't work.
(1) Historically, C compilers ran a chain of programs over the source (then memories where measured in KiB, not GiB), the first --preprocessor-- was usually called cpp; today's compilers usually don't have a separate preprocessor anymore. But conceptually the first step is still preprocessing the code (handle #include, #if and #defined macros).
I think you're misunderstand how the historical 'the value is not set' works.
In the C preprocessor, whenever you have an #if directive any identifier in the expression that is not an macro (and is not the special function defined) will be replaced by the constant 0 prior to evaluating the #if. So with your example
#define VALUE get_value()
#if VALUE == 0
what happens is the VALUE macro is expanded, then, since there is no get_value macro defined, it is replaced by 0, leaving you with
#if 0() == 0
which gives you the syntax error you see.
Macro to replace undefined tokens with some predefined value.
I would like to have some EXPAND(x) macro that will expand to x if x is defined and to, for example, -1 if it is not, so that this code:
#define M1 1
#define M2 2
#undef M3
#define M4 (2*2)
printf("%i %i %i %i", EXPAND(M1), EXPAND(M2), EXPAND(M3), EXPAND(M4));
would print:
1 2 -1 4
Is that possible in C? Only thing that I can think of is to stringify x and then parse it with constexpr function, but that will work only in simple cases.
The only way to do this would be to use some header file that knows all possible macros and checks if they are defined. If not, replace them with -1.
#ifndef M1
#define M1 -1
#endif
#ifndef M2
#define M2 -1
#endif
...
You would then include this header after the file containing the macros/after the macro defines.
Though please note that this is a bad design, full of tight coupling and other incredibly bad ideas. There's certainly better ways to solve the actual problem, like ensuring that the code won't compile if a certain macro is missing.
I wonder if it is possible to build a gnu C macro which expands to a list of tokens (integer numbers) which are the arguments of the macro without duplicates. The number of arguments could be assumed fixed (for the moment). I.e. I want something like:
#define MAC(a,b,c) ???
which expands e.g.
MAC(1,2,1)
to 1,2.
The arguments are not sorted and the result does not have to be.
Based on the proposal below I built an example which does essentially what I want using the p99 includes:
#include <p99/p99_if.h>
#include <p99/p99_paste.h>
#define MAC2(a,b) double P99_PASTE2(myvar_, a) P99_IF_EQ(a,b)()(; double P99_PASTE2(myvar_, b))
#define MAC3(a,b,c) double P99_PASTE2(myvar_, a) P99_IF_EQ(a,b)()(; double P99_PASTE2(myvar_, b)) P99_IF_EQ(a,c)()(P99_IF_EQ(b,c)()(; double P99_PASTE2(myvar_, c)) )
MAC2(1,2);
MAC2(3,3);
MAC3(1,2,3);
MAC3(10,10,1);
If your arguments are always small decimal numbers as in your example, you could get away with what I provide in P99. It has macros like P99_IF_EQ that you could use as
#define MAC(A,B) unsigned P99_PASTE2(myvar_, A) P99_IF_EQ(A,B)()(; unsigned P99(unsigned P99_PASTE2(myvar_, B))
MAC(1,2); // -> myvar_1 and myvar_2
MAC(3,3); // -> myvar_3
to only expand the declaration for B if it is not equal to A. Obviously for three different arguments this already becomes a bit tedious, but would be doable.
As the questions says, is the C preprocessor able to do it?
E.g.:
#define PI 3.1416
#define OP PI/100
#define OP2 PI%100
Is there any way OP and/or OP2 get calculated in the preprocessing phase?
Integer arithmetic? Run the following program to find out:
#include "stdio.h"
int main() {
#if 1 + 1 == 2
printf("1+1==2\n");
#endif
#if 1 + 1 == 3
printf("1+1==3\n");
#endif
}
Answer is "yes", there is a way to make the preprocessor perform integer arithmetic, which is to use it in a preprocessor condition.
Note however that your examples are not integer arithmetic. I just checked, and gcc's preprocessor fails if you try to make it do float comparisons. I haven't checked whether the standard ever allows floating point arithmetic in the preprocessor.
Regular macro expansion does not evaluate integer expressions, it leaves it to the compiler, as can be seen by preprocessing (-E in gcc) the following:
#define ONEPLUSONE (1 + 1)
#if ONEPLUSONE == 2
int i = ONEPLUSONE;
#endif
Result is int i = (1 + 1); (plus probably some stuff to indicate source file names and line numbers and such).
The code you wrote doesn't actually make the preprocessor do any calculation. A #define does simple text replacement, so with this defined:
#define PI 3.1416
#define OP PI/100
This code:
if (OP == x) { ... }
becomes
if (3.1416/100 == x) { ... }
and then it gets compiled. The compiler in turn may choose to take such an expression and calculate it at compile time and produce a code equivalent to this:
if (0.031416 == x) { ... }
But this is the compiler, not the preprocessor.
To answer your question, yes, the preprocessor CAN do some arithmetic. This can be seen when you write something like this:
#if (3.141/100 == 20)
printf("yo");
#elif (3+3 == 6)
printf("hey");
#endif
YES, I mean: it can do arithmetic :)
As demonstrated in 99 bottles of beer.
Yes, it can be done with the Boost Preprocessor. And it is compatible with pure C so you can use it in C programs with C only compilations. Your code involves floating point numbers though, so I think that needs to be done indirectly.
#include <boost/preprocessor/arithmetic/div.hpp>
BOOST_PP_DIV(11, 5) // expands to 2
#define KB 1024
#define HKB BOOST_PP_DIV(A,2)
#define REM(A,B) BOOST_PP_SUB(A, BOOST_PP_MUL(B, BOOST_PP_DIV(A,B)))
#define RKB REM(KB,2)
int div = HKB;
int rem = RKB;
This preprocesses to (check with gcc -S)
int div = 512;
int rem = 0;
Thanks to this thread.
Yes.
I can't believe that no one has yet linked to a certain obfuscated C contest winner. The guy implemented an ALU in the preprocessor via recursive includes. Here is the implementation, and here is something of an explanation.
Now, that said, you don't want to do what that guy did. It's fun and all, but look at the compile times in his hint file (not to mention the fact that the resulting code is unmaintainable). More commonly, people use the pre-processor strictly for text replacement, and evaluation of constant integer arithmetic happens either at compile time or run time.
As others noted however, you can do some arithmetic in #if statements.
Be carefull when doing arithmetic: add parenthesis.
#define SIZE4 4
#define SIZE8 8
#define TOTALSIZE SIZE4 + SIZE8
If you ever use something like:
unsigned int i = TOTALSIZE/4;
and expect i to be 3, you would get 4 + 2 = 6 instead.
Add parenthesis:
#define TOTALSIZE (SIZE4 + SIZE8)