29

I'm creating a macro in C++ that declares a variable and assigns some value to it. Depending on how the macro is used, the second occurrence of the macro can override the value of the first variable. For instance:

#define MY_MACRO int my_variable_[random-number-here] = getCurrentTime();

The other motivation to use that is to avoid selecting certain name to the variable so that it be the same as a name eventually chosen by the developer using the macro.

Is there a way to generate random variable names inside a macro in C++?

-- Edit --

I mean unique but also random once I can use my macro twice in a block and in this case it will generate something like:

int unique_variable_name;
...
int unique_variable_name;

In this case, to be unique both variable names have to be random generated.

freitass
  • 6,542
  • 5
  • 40
  • 44
  • 3
    Surely you mean unique variable names, rather than random? –  Jul 04 '09 at 15:23
  • 1
    I'm a bit confused about how this would be useful. Does the programmer then get to make some use of the my_variable_* references later? does getCurrentTime() have some useful side effect? – SingleNegationElimination Jul 04 '09 at 18:23
  • There's an SO answer on random MACRO numbers: https://stackoverflow.com/a/17420032/3353857, based on http://www.ciphersbyritter.com/NEWS4/RANDC.HTM – caoanan May 28 '20 at 04:31

8 Answers8

47

Try the following:

// One level of macro indirection is required in order to resolve __COUNTER__,
// and get varname1 instead of varname__COUNTER__.
#define CONCAT(a, b) CONCAT_INNER(a, b)
#define CONCAT_INNER(a, b) a ## b

#define UNIQUE_NAME(base) CONCAT(base, __COUNTER__)

void main() {
  int UNIQUE_NAME(foo) = 123;  // int foo0 = 123;
  std::cout << foo0;           // prints "123"
}

__COUNTER__ may have portability issues. If this is a problem, you can use __LINE__ instead and as long as you aren't calling the macro more than once per line or sharing the names across compilation units, you will be just fine.

Dave Dopson
  • 41,600
  • 19
  • 95
  • 85
  • This looks crazy, but it actually works. I had exactly this problem: `__LINE__` expanding to itself, instead of a number. I left out the `PP_`, and now I can do things like: `#define FOR(ii, ll, uu) int CAT(FORlim, __LINE__) = (uu); for(int ii = (ll); ii < CAT(FORlim, __LINE__); ++ii)` - which are not possible with any `while(0)`-hacks. This answer should be way higher. – Tomasz Gandor Nov 18 '13 at 05:22
  • 1
    And how to reference a variable with just formed unique name? Say, I have this code: int UNIQUE_NAME(nTest) = 100;. How to query that nTest0 variable later in the code? PP_CAT(base, __COUNTER - 1) does not work. Thanks. – Roman Jan 04 '18 at 04:28
  • for why we need indirection in macro, read https://stackoverflow.com/a/13301627/264047 – Alexander Malakhov Jan 24 '18 at 17:55
  • @Alexander Malakhov Thank you for the link, I have tried various ways of indirections without success. It would be great if you could share a variant of UNIQUE_PREV_NAME(base) if you can make one. – Roman Feb 01 '18 at 16:49
  • @Roman the only counter-based thing I can think of is `#define UNIQUE_PREV_NAME(base) PP_CAT(base, __COUNTER__ - 1)`. Obviously, it's very limited - you can use it only once after each `UNIQUE_NAME` expansion... If you need to reference previous name inside same macro, I would play with something like `#define UNIQUE_NAME(base) PP_CAT(__FILENAME__, __LINE__)` - remember that from compiler's point of view whole macro is defined on a single line (continuation '\' doesn't count) => hence, `__LINE__` will exapand to the same thing – Alexander Malakhov Feb 02 '18 at 11:48
  • 1
    @Alexander Malakhov I have played with all sorts of __COUNTER - 1 I could imagine. Experiments on godbolt (with -E gcc key) result in a conclusion that it's simply not doable: there is no way to make the preprocessor shrink the math expression (it won't transform "10 - 1" to "9", for instance). Thanks for your help anyway. – Roman Feb 02 '18 at 17:19
  • @Roman ah, "10 - 1", you're right. Didn't `__LINE__`-based solution work? I have couple other ideas on how to do that, but it all depends on the context. I think this discussion is already too lengthy for comments. Please, create new question post and feel free to ping me here with a link. – Alexander Malakhov Feb 06 '18 at 09:59
  • @Roman I've used `__LINE__` to generate unique label name and reference it later in [this post](https://stackoverflow.com/a/42145840/264047), see macro `CALL_IMPL` (it's a looong one, scroll down to point "10. No calls"") – Alexander Malakhov Feb 06 '18 at 10:08
  • @Alexander Malakhov Thank you for the link, now I have something interesting to read I was not going to read about :-) – Roman Feb 07 '18 at 06:23
17

use __COUNTER__ (works on gcc4.8, clang 3.5 and Intel icc v13, MSVC 2015)

#define CONCAT_(x,y) x##y
#define CONCAT(x,y) CONCAT_(x,y)
#define uniquename static bool CONCAT(sb_, __COUNTER__) = false
ACyclic
  • 5,904
  • 6
  • 26
  • 28
benoit
  • 179
  • 1
  • 2
16

Add M4 to your build flow? This macro language has some stateful capabilities, and can successfully be intermingled with CPP macros. This is probably not a standard way to generate unique names in a C environment, though I've been able to sucessfully use it in such a manner.

You probably do not not want random, BTW, based on the way you posed your question. You want unique.

You could use __FILE__ and __LINE__ in the macro expansion to get you the uniqueness you seem to be going for... those metavariables get defined within the source file context, so be careful to make sure you get what you are looking for (e.g., perils of more than one macro on the same line).

popcnt
  • 4,519
  • 1
  • 16
  • 14
  • 5
    There is also the __COUNTER__ macro which generates new integer every time it is invoked, but it is non-standard. – Adam Rosenfield Jul 04 '09 at 15:03
  • 2
    Whoa, SO has comment formatting now! Anyways, that should really be COUNTER with two underscores preceding and following it. – Adam Rosenfield Jul 04 '09 at 15:04
  • 5
    This won't work for me since I may use the macro more than once inside the same file and reference it later in another macro. The "__ COUNTER __" (I know it is all together) may work but I would need to know the current value of the counter without incrementing it. – freitass Jul 05 '09 at 19:47
  • could you not #define A_VAR UNIQUE_VAR_MACRO() \n int A_VAR = 1; printf("%x",A_VAR);.... #UNDEF A_VAR ?? – KitsuneYMG Nov 04 '09 at 17:07
  • @freitass - look at Dave Dopson's answer below. I wanted to use `__LINE__` in my macro, and when token-pasting with `##` it just pasted `__LINE__`. However, this can be hacked around. My example from there is, however, possible to solve without this hack, via `#define FOR(ii, ll, uu) for(int ii##lim = (uu), ii = (ll); ii < ii##lim; ++ii)`. - but this is C++ or C99 (for scoping). A similar `FOR`-macro for old C would need Dave's technology. – Tomasz Gandor Nov 18 '13 at 05:32
8

Generating unique names in the preprocessor is difficult. The closest you can get is to mangle __FILE__ and __LINE__ into the symbol as popcnt suggests. If you really need to generate unique global symbol names, then I would follow his suggestion about using something like M4 or a Perl script in your build system instead.

You might not need unique names. If your macro can impose a new scope, then you can use the same name since it will simply shadow other definitions. I usually follow the common advice of wrapping macros in do { ... } while (0) loops. This only works for macros which are statements - not expressions. The macro can update variables using output parameters. For example:

#define CALC_TIME_SINCE(t0, OUT) do { \
     std::time_t _tNow = std::time(NULL); \
     (OUT) = _tNow - (t0); \
} while (0)

If you follow a few rules, you are usually pretty safe:

  1. Use leading underscores or similar naming conventions for symbols defined within the macro. This will prevent problems associated with a parameter using the same symbol from occurring.
  2. Only use the input parameters once and always surround them with parentheses. This is the only way to make macros work with expressions as input.
  3. Use the do { ... } while (0) idiom to ensure that the macro is only used as a statement and to avoid other textual replacement problems.
Community
  • 1
  • 1
D.Shawley
  • 58,213
  • 10
  • 98
  • 113
  • 2
    Using leading underscores is not a good idea, as names thus generated may clash with implementation reserved names, and are in any case reserved themselves. –  Jul 04 '09 at 14:58
  • 1
    Indeed. It's possible the macro's user might want to use a name like _tNow. I'll suggest using the full macro name as a prefix for the names used by the macro, in this case CALC_TIME_SINCE_tNow – SingleNegationElimination Jul 04 '09 at 18:30
3

Instead of having the preprocesser create a name, you could possibly let the macro user give you a name.

#define MY_MACRO(varname) int varname = getCurrentTime();
SingleNegationElimination
  • 151,563
  • 33
  • 264
  • 304
2

I needed something similar for a case where I didn't have any profiling tools, but I wanted to count how many threads were inside a particular block of code as well as the amount of time (ticks) spent in that block of code by each thread, In this case every block needed a unique static variable accessible to all threads, and I needed to later reference that variable to incr (I used a logging API rather than printf in the actual code, but this works as well). At first I thought I was very clever by doing the following:

#define PROF_START { \
    static volatile int entry_count##___FUNCTION__##__LINE__ = 0; int *ptc = &entry_count##___FUNCTION__##__LINE__; \
    clock_t start, end; \
    start = times(0); \
    (*ptc)++;

But then I realized this is just silly and the C compiler will simply do this for you, as long as each "static" declaration is its own block:

#include <stdio.h>
#include <sys/times.h>

#define PROF_START { \
    static int entry_count = 0; \
    clock_t start, end; \
    start = times(0); \
    entry_count++;


#define PROF_END \
    end = times(0); \
    printf("[%s:%d] TIMER: %ld:%d\n" , __FUNCTION__, __LINE__, end-start, entry_count); \
    entry_count--; \
    }

Note the open/close brackets in each macro. This isn't strictly thread-safe, but for my profiling purposes I could assume the incr and decr operations were atomic. Here's a recursion sample which uses the macros

#define ITEM_COUNT 5

struct node {
   int data;
   struct node *next;
 };

revsort(struct node **head)
{
  struct node *current = *head;
  struct node *next_item;

  while (current->next)
  {
PROF_START
    next_item = current->next;
    current->next = next_item->next;
    next_item->next = *head;
    *head = next_item;
PROF_END
  }
}

rrevsort(struct node **head)
{
  struct node *current = *head;
  struct node *next_item = current->next;

PROF_START
  current->next = 0;
  if (next_item)
  {
   *head = next_item;
    rrevsort(head);
    next_item->next = current;
  }
PROF_END

}

printnode(struct node *head)
{
  if (head)
  {
    printf("%d ", head->data);
    printnode(head->next);
  }
  else
    printf("\n");

}

main()
{

  struct node node_list[ITEM_COUNT];
  struct node *head = &node_list[0];
  int i;

  for (i=0; i < ITEM_COUNT - 1; i++)
  {
PROF_START
      node_list[i].data = i;
      node_list[i].next = &node_list[i+1];
PROF_END
  }
  node_list[i].data = i;
  node_list[i].next = 0;

  printf("before\n");
  printnode(head);
  revsort(&head);
  printf("after\n");
  printnode(head);
  rrevsort(&head);
  printf("before\n");
  printnode(head);
}

Extra hint, the above program is a common interview question. Excerpt from "nm -A":

macro:0804a034 b entry_count.1715
macro:0804a030 b entry_count.1739
macro:0804a028 b entry_count.1768
macro:0804a02c b entry_count.1775
Mike Patnode
  • 416
  • 5
  • 14
1

Here is a succinct macro definition to generate the singleton pattern above.

#define SINGLETON_IMPLIMENTATION(CLASS_NAME) static CLASS_NAME *g##CLASS_NAME = nil; + (CLASS_NAME *)instance { @synchronized(self) { if (g##CLASS_NAME == nil) g##CLASS_NAME = [self new]; } return g##CLASS_NAME; }

#define SINGLETON_DECLARATION(CLASS_NAME) + (CLASS_NAME *)instance;
bbrame
  • 18,031
  • 10
  • 35
  • 52
-1

While I don't think its even possible, you should seriously consider making a class out of this.

If you want a random element in a random array to hold a certain value, you can do this:

std::vector< std::vector<int> > m_vec;

Then wrap it in a class, so the developer can only set a number:

void set(int foo)
{
    m_vec[random()][random()] = foo;
}

Is there any reason why you want it a macro? Random variable name sounds dangerous, what if it picks something already defined somewhere else in the code?

Mizipzor
  • 51,151
  • 22
  • 97
  • 138
  • Actually I don't "want" it a macro, but the problem to be solved is into a macro. Your answer gave me an idea, I have created a class to hold the values (managing a list instead of declaring a variable each time). – freitass Jul 05 '09 at 19:42