如何使用宏在 C++ 中生成随机变量名称?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1082192/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to generate random variable names in C++ using macros?
提问by freitass
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:
我在 C++ 中创建了一个宏,它声明了一个变量并为其分配了一些值。根据宏的使用方式,第二次出现的宏可以覆盖第一个变量的值。例如:
#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++?
有没有办法在 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.
在这种情况下,为了唯一,两个变量名称都必须随机生成。
采纳答案by popcnt
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.
将 M4 添加到您的构建流程中?这种宏语言具有一些状态功能,可以成功地与 CPP 宏混合使用。这可能不是在 C 环境中生成唯一名称的标准方法,尽管我已经能够以这种方式成功使用它。
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).
您可以在宏扩展中使用__FILE__
和__LINE__
来获得您似乎想要的唯一性...这些元变量在源文件上下文中定义,因此请小心确保您获得所需的内容(例如,风险同一行上有多个宏)。
回答by Dave Dopson
Try the following:
请尝试以下操作:
// 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__
is rumored to have portability issues. If so, 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.
__COUNTER__
传闻有便携性问题。如果是这样,您可以__LINE__
改用,只要您不是每行多次调用宏或跨编译单元共享名称,就可以了。
回答by benoit
use __COUNTER__
(works on gcc4.8, clang 3.5 and Intel icc v13, MSVC 2015)
使用__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
回答by D.Shawley
Generating unique names in the preprocessor is difficult. The closest you can get is to mangle __FILE__
and __LINE__
into the symbol as popcntsuggests. 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.
在预处理器中生成唯一名称很困难。您能得到的最接近的方法是按照popcnt 的建议将符号分解__FILE__
并__LINE__
插入符号中。如果您真的需要生成唯一的全局符号名称,那么我会遵循他的建议,在您的构建系统中使用 M4 或 Perl 脚本之类的东西。
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:
您可能不需要唯一的名称。如果您的宏可以强加一个新的作用域,那么您可以使用相同的名称,因为它只会掩盖其他定义。我通常遵循在do { ... } while (0)
循环中包装宏的常见建议。这仅适用于作为语句的宏 - 而不是表达式。宏可以使用输出参数更新变量。例如:
#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:
如果你遵循一些规则,你通常是很安全的:
- 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.
- 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.
- Use the
do { ... } while (0)
idiom to ensure that the macro is only used as a statement and to avoid other textual replacement problems.
- 对宏中定义的符号使用前导下划线或类似的命名约定。这将防止发生与使用相同符号的参数相关的问题。
- 只使用一次输入参数,并始终用括号将它们括起来。这是使宏使用表达式作为输入的唯一方法。
- 使用
do { ... } while (0)
习惯用法可确保宏仅用作语句并避免其他文本替换问题。
回答by SingleNegationElimination
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();
回答by Mike Patnode
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:
对于我没有任何分析工具的情况,我需要类似的东西,但我想计算特定代码块中有多少线程以及每个代码块在该代码块中花费的时间(滴答声)线程,在这种情况下,每个块都需要一个所有线程都可以访问的唯一静态变量,我稍后需要将该变量引用到 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)++;
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:
但后来我意识到这只是愚蠢的,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--; \
}
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
注意每个宏中的开/关括号。这不是严格的线程安全的,但为了我的分析目的,我可以假设 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);
}
Extra hint, the above program is a common interview question. Excerpt from "nm -A":
额外提示,上面的程序是一个常见的面试问题。摘自“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
回答by bbrame
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;
回答by Mizipzor
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?
你有什么理由想要一个宏吗?随机变量名称听起来很危险,如果它选择了代码中其他地方已经定义的东西怎么办?