如何使用宏在C ++中生成随机变量名?

时间:2009-07-04 13:16:54

标签: c++ variables random macros naming

我在C ++中创建一个宏来声明一个变量并为它赋值。根据宏的使用方式,宏的第二次出现可以覆盖第一个变量的值。例如:

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

使用它的另一个动机是避免为变量选择某个名称,以使其与开发人员最终使用宏选择的名称相同。

有没有办法在C ++中的宏内生成随机变量名?

- 编辑 -

我的意思是独特但也是随机的,一旦我可以在一个块中使用我的宏两次,在这种情况下它会产生类似的东西:

int unique_variable_name;
...
int unique_variable_name;

在这种情况下,为了唯一,两个变量名必须是随机生成的。

8 个答案:

答案 0 :(得分:22)

尝试以下方法:

// This is some crazy magic that helps produce __BASE__247
// Vanilla interpolation of __BASE__##__LINE__ would produce __BASE____LINE__
// I still can't figure out why it works, but it has to do with macro resolution ordering
#define PP_CAT(a, b) PP_CAT_I(a, b)
#define PP_CAT_I(a, b) PP_CAT_II(~, a ## b)
#define PP_CAT_II(p, res) res

#define UNIQUE_NAME(base) PP_CAT(base, __COUNTER__)
传闻

__COUNTER__存在可移植性问题。如果是这样,您可以使用__LINE__代替,只要您不是每行调用一次宏或在编译单元之间共享名称,您就可以了。

答案 1 :(得分:12)

将M4添加到您的构建流程中?这种宏语言具有一些有状态功能,可以成功地与CPP宏混合。这可能不是在C环境中生成唯一名称的标准方法,尽管我已经能够以这种方式成功使用它。

根据你提出问题的方式,你可能根本不想要随机BTW。您想要唯一

你可以在宏扩展中使用__FILE____LINE__来获得你想要的唯一性...那些元变量在源文件上下文中被定义,所以要小心确定你得到了你想要的东西(例如,在同一条线上有多个宏的危险)。

答案 2 :(得分:10)

使用__COUNTER__(适用于gcc4.8,clang 3.5和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

答案 3 :(得分:8)

在预处理器中生成唯一名称很困难。您可以获得的最接近的是将__FILE____LINE__变为符号popcnt。如果你真的需要生成唯一的全局符号名称,那么我会遵循他关于在你的构建系统中使用类似M4或Perl脚本的建议。

您可能不需要唯一的名称。如果您的宏可以强加一个新范围,那么您可以使用相同的名称,因为它只会影响其他定义。我通常遵循在do { ... } while (0)循环中包装宏的常见建议。这仅适用于作为语句的宏 - 而不是表达式。宏可以使用输出参数更新变量。例如:

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

如果您关注few rules,通常会非常安全:

  1. 对宏中定义的符号使用前导下划线或类似的命名约定。这将防止与使用相同符号的参数相关的问题。
  2. 仅使用输入参数一次,并始终用括号括起来。这是使宏使用表达式作为输入的唯一方法。
  3. 使用do { ... } while (0)惯用法确保宏仅用作语句并避免其他文本替换问题。

答案 4 :(得分:3)

您可以让宏用户为您命名,而不是让preprocesser创建名称。

#define MY_MACRO(varname) int varname = getCurrentTime();

答案 5 :(得分:1)

对于我没有任何分析工具的情况,我需要类似的东西,但我想计算特定代码块中有多少个线程以及在该块中花费的时间(滴答)。每个线程的代码,在这种情况下,每个块都需要一个可供所有线程访问的唯一静态变量,我需要稍后将该变量引用到incr(我在实际代码中使用了日志API而不是printf,但这也有效) 。起初,我认为通过以下方式我非常聪明:

#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)++;

但后来我意识到这只是愚蠢的,C编译器只会为你做这个,只要每个“静态”声明都是它自己的块:

#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--; \
    }

注意每个宏中的打开/关闭括号。这不是严格的线程安全的,但对于我的分析目的,我可以假设incr和decr操作是原子的。这是一个使用宏

的递归示例
#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);
}

额外提示,上述计划是一个常见的面试问题。摘自“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

答案 6 :(得分:1)

这是一个简洁的宏定义,用于生成上面的单例模式。

#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;

答案 7 :(得分:0)

虽然我认为它甚至不可能,但你应该认真考虑从中做出一个课程。

如果您希望随机数组中的随机元素保持特定值,则可以执行以下操作:

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

然后将它包装在一个类中,因此开发人员只能设置一个数字:

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

你有什么理由想要它吗?随机变量名称听起来很危险,如果它选择已在代码中其他地方定义的内容会怎样?