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

发布于 2024-07-25 17:04:44 字数 456 浏览 2 评论 0原文

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

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

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

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

-- 编辑 --

我的意思是唯一的,但也是随机的,一旦我可以在一个块中使用我的宏两次,在这种情况下,它将生成类似的内容:

int unique_variable_name;
...
int unique_variable_name;

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

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

苹果你个爱泡泡 2024-08-01 17:04:44

请尝试以下操作:

// 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__ 可能存在可移植性问题。 如果这是一个问题,您可以使用 __LINE__ 代替,只要您每行调用宏的次数不超过一次或在编译单元之间共享名称,就可以了。

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.

何止钟意 2024-08-01 17:04:44

使用 __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

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
逆光下的微笑 2024-08-01 17:04:44

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

顺便说一句,根据您提出问题的方式,您可能不希望随机。 您想要独一无二

您可以在宏扩展中使用 __FILE__ 和 __LINE__ 来获得您想要的唯一性...这些元变量是在源文件上下文中定义的,因此小心确保你得到你正在寻找的东西(例如,同一行上有多个宏的危险)。

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).

无尽的现实 2024-08-01 17:04:44

在预处理器中生成唯一的名称很困难。 您可以获得的最接近的方法是将 __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)

如果您遵循一些规则,那么您通常非常安全:

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

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.
桃酥萝莉 2024-08-01 17:04:44

您可以让宏用户给您一个名称,而不是让预处理器创建名称。

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

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();
酒几许 2024-08-01 17:04:44

对于没有任何分析工具的情况,我需要类似的东西,但我想计算特定代码块内有多少线程以及每个线程在该代码块中花费的时间(滴答声)线程,在这种情况下,每个块都需要一个可供所有线程访问的唯一静态变量,并且我需要稍后将该变量引用到 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

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
软的没边 2024-08-01 17:04:44

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

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

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;
把昨日还给我 2024-08-01 17:04:44

虽然我认为这根本不可能,但你应该认真考虑以此为基础开设一门课程。

如果你希望随机数组中的随机元素保存某个值,你可以这样做:

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

然后将其包装在一个类中,这样开发人员只能设置一个数字:

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

有什么理由让你想要它是一个宏吗? 随机变量名听起来很危险,如果它选择了代码中其他地方已经定义的东西怎么办?

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?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文