0

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);
Morwenn
  • 21,684
  • 12
  • 93
  • 152
highsciguy
  • 2,569
  • 3
  • 34
  • 59
  • Pretty hard to imagine why you would prefer to write `MAC(1,2,1)` rather than simply writing `1,2`. – David Heffernan Dec 12 '12 at 09:48
  • Admittedly the application is not obvious. I want to define a set of variables which depends on the indices (which are the arguments of MAC). But the three indices over-determine the variables. Only part of the information is needed. Of course I could reduce the list of indices by hand, but this would lead to inconsistent code if I make mistakes. – highsciguy Dec 12 '12 at 09:51
  • 2
    why not write a function looking like `int * unique_list(int*, int )` or `void remove_duplicates(int *, int)` – UmNyobe Dec 12 '12 at 09:53
  • @UmNyobe: the expression needs to be expanded before compilation as it should determine variable names. – highsciguy Dec 12 '12 at 09:54

1 Answers1

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.

Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177
  • I decided o give it a try. It has different features I could use. I downloaded and successfully compiled test examples with gcc. Strangely with `icc -I /usr/local/include/p99 -Wall -c -o test-p99-double -std=c99 test-p99-double.c` (version 13.0.1) I get: `/usr/local/include/p99/p99_block.h(473): error: expected a ";" void p00_longjmp(p00_jmp_buf0 * p00_buf, int p00_val) { ^ test-p99-double.c(56): warning #12: parsing restarts here after previous syntax error P99_IS_GT(1, 1);` and many more. What am I doing wrong? – highsciguy Dec 12 '12 at 13:20
  • This lacks a closing round bracket. I modified your answer as to account for three indices, see my modified question. Unfortunately I still don't get it to work with icc. The preprocessor produces code which does not compile. – highsciguy Dec 12 '12 at 14:04
  • I found that it compiles with `icc` when omitting `#line` directives: `icc -I /usr/local/include -std=c99 -P -o test test.c` – highsciguy Dec 12 '12 at 14:15
  • @highsciguy, AFAIR icc has problems with C99. And since it is not free, I don't always have a version available for testing. Could you please send me a detailed report and/or patch through other chanels? Thanks. – Jens Gustedt Dec 12 '12 at 15:21