C Macro to remove duplicates in list of arguments - c

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.

Related

Macros #if directive with non integer definition

I'm having a 20yo legacy code (pure C) which defines:
#define X float
before first function and before another function:
#undefine X
#define X double
I'm writing a code which is supposed to work with both definitions (and it'll be copied into both functions automatically). But it's impossible to make such code in a few cases. For these cases I need to detect if my X is float or double and use #if #else #endif.
The #if (X == float) is resolved as 0 == 0 and won't work.
In theory I can grab into legacy code and modify these definition to make my life easier, but I wonder if there is any macro magic which would allow me to workaround this without touching the legacy? Something with conversion X to string may be? Any ideas?
Concatenate with prefix that expands to something you can control.
#define PREFIX_float 0
#define PREFIX_double 1
#define CONCAT(a, b) a##b
#define XCONCAT(a, b) CONCAT(a, b)
#if XCONCAT(PREFIX_, X) == PREFIX_float

Variadic macro that outputs its arguments separated by `||`

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.

double scientific notation in macro

I was wondering if I can create macro that creating value with custom "shift" (or other way to create it in compile time). I mean, concatenate two numbers or something...
Something like that (of course it's not working):
#define CUSTOM_DOUBLE(shift) 1.05E shift
I know I can do:
#define CUSTOM_DOUBLE(shift) 1.05 * pow(10.0, shift)
But I'm aware that it isn't calculated in compile time.
As long as shift argument is passed as integer constant (of decimal form) this can be accomplished by ## operator, that concatenates preprocessing tokens. For instance, it may be implemented as:
#include <stdio.h>
#define CUSTOM_DOUBLE(shift) (1.05E ## shift)
int main(void)
{
double d = CUSTOM_DOUBLE(3);
printf("%E\n", d);
return 0;
}
You want this:
#define CUSTOM_DOUBLE(shift) 1.05E##shift
## is the concatenation operator.

x-macro conditional error - number comparison

I would like to generate compile time error for X-macro for all X(a, b) where a > b
/* X(a, b) */
#define LIST \
X(10, 20) \
X(5, 20) \
X(30, 20) \
X(1, 20)
So, generate error for X(30, 20)
Is this possible in C?
EDIT: example usage
For me, left number is for example sizeof of some large struct and right number is fixed space to store this struct. If the struct is bigger then available space, I need compiler to generate error.
//e.g.
X(sizeof(struct conf), 2*PAGE)
Yes, here's a proof of concept:
#pragma push_macro("X")
#undef X
#define X(a,b) typedef int x[(a>b)?-1:1];
LIST
#pragma pop_macro("X")
So, we define X to define a type of array of ints, with either -1 or 1, depending whether a is greater than b. If it is, the array of -1 elements will cause an error.
If using C11, the typedef line can be done using static_assert(a<=b) from assert.h
It is possible in C11 by using the _Static_assert keyword:
#define X( a , b ) _Static_assert( a <= b , "Error!" )
Note that expressions a and b must be constant.

Can the C preprocessor perform integer arithmetic?

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)

Resources