如何在C预处理器中生成唯一值?

时间:2022-06-09 08:53:37

I'm writing a bunch of related preprocessor macros, one of which generates labels which the other one jumps to. I use them in this fashion:

我正在编写一堆相关的预处理器宏,其中一个生成另一个跳转到的标签。我以这种方式使用它们:

MAKE_FUNNY_JUMPING_LOOP(
  MAKE_LABEL();
  MAKE_LABEL();
)

I need some way to generate unique labels, one for each inner MAKE_LABEL call, with the preprocessor. I've tried using __LINE__, but since I call MAKE_LABEL inside another macro, they all have the same line and the labels collide.

我需要一些方法来生成唯一标签,每个内部MAKE_LABEL调用一个,使用预处理器。我尝试过使用__LINE__,但是因为我在另一个宏中调用了MAKE_LABEL,所以它们都有相同的行并且标签发生冲突。

What I'd like this to expand to is something like:

我想要扩展到的是:

MAKE_FUNNY_JUMPING_LOOP(
  my_cool_label_1:  // from first inner macro
  ...
  my_cool_label_2:  // from second inner macro
  ...
)

Is there a way to generate hashes or auto-incrementing integers with the preprocessor?

有没有办法用预处理器生成哈希值或自动递增整数?

6 个解决方案

#1


As others noted, __COUNTER__ is the easy but nonstandard way of doing this.

正如其他人所说,__ COUNTER__是这样做的简单但非标准的方式。

If you need extra portability, or for other cool preprocessor tricks, the Boost Preprocessor library (which works for C as well as C++) will work. For example, the following header file will output a unique label wherever it's included.

如果您需要额外的可移植性或其他很酷的预处理器技巧,Boost预处理器库(适用于C和C ++)将起作用。例如,以下头文件将在包含它的任何位置输出唯一标签。

#include <boost/preprocessor/arithmetic/inc.hpp>
#include <boost/preprocessor/slot/slot.hpp>

#if !defined(UNIQUE_LABEL)
#define UNIQUE_LABEL
#define BOOST_PP_VALUE 1
#include BOOST_PP_ASSIGN_SLOT(1)
#undef BOOST_PP_VALUE
#else
#define BOOST_PP_VALUE BOOST_PP_INC(BOOST_PP_SLOT(1))
#include BOOST_PP_ASSIGN_SLOT(1)
#undef BOOST_PP_VALUE
#endif


BOOST_PP_CAT(my_cool_label_, BOOST_PP_SLOT(1)):

Sample:

int main(int argc, char *argv[]) {
    #include "unique_label.h"
    printf("%x\n", 1234);
    #include "unique_label.h"
    printf("%x\n", 1234);
    #include "unique_label.h"
    return 0;
}

preprocesses to

int main(int argc, char *argv[]) {
    my_cool_label_1:
    printf("%x\n", 1234);
    my_cool_label_2:
    printf("%x\n", 1234);
    my_cool_label_3:
    return 0;
}

#2


If you're using GCC or MSVC, there is __COUNTER__.

如果您使用的是GCC或MSVC,则有__COUNTER__。

Other than that, you could do something vomit-worthy, like:

除此之外,你可以做一些呕吐物,比如:

#ifndef USED_1
#define USED_1
1
#else
#ifndef USED_2
#define USED_2
2
/* many many more */
#endif
#endif

#3


I use this:

我用这个:

#define MERGE_(a,b)  a##b
#define LABEL_(a) MERGE_(unique_name_, a)
#define UNIQUE_NAME LABEL_(__LINE__)

int main()
{
    int UNIQUE_NAME = 1;
    return 0;
}

... and get the following:

...并获得以下内容:

int main()
{
    int unique_name_8 = 1;
    return 0;
}

#4


I can't think of a way to automatically generate them but you could pass a parameter to MAKE_LABEL:

我想不出自动生成它们的方法,但您可以将参数传递给MAKE_LABEL:

#define MAKE_LABEL(n) my_cool_label_##n:

Then...

MAKE_FUNNY_JUMPING_LOOP(
  MAKE_LABEL(0);
  MAKE_LABEL(1);
)

#5


You could do this:

你可以这样做:

#define MAKE_LABEL() \
do {                 \   
my_cool_label:       \
/* some stuff */;    \
goto my_cool_label;  \
/* other stuff */;   \
} while (0) 

This keeps the scope of the label local, allowing any number of them inside the primary macro.

这使标签的范围保持在本地,允许在主宏中包含任意数量的标签。

If you want the labels to be accessed more globally, it's not clear how your macro "MAKE_FUNNY_JUMPING_LOOP" references these labels. Can you explain?

如果您希望更全面地访问标签,则不清楚宏“MAKE_FUNNY_JUMPING_LOOP”如何引用这些标签。你可以解释吗?

#6


It doesn't seem possible with a standard preprocessor, although you could fake it out by putting parameters within MAKE_LABEL or MAKE_FUNNY_JUMPING_LOOP, and use token pasting to create the label.

使用标准预处理器似乎不太可能,尽管您可以通过在MAKE_LABEL或MAKE_FUNNY_JUMPING_LOOP中放置参数来伪造它,并使用标记粘贴来创建标签。

There's nothing preventing you from making your own preprocessing script that does the automatic increment for you. However, it won't be a standard C/C++ file in that case.

没有什么可以阻止您制作自己的预处理脚本来为您自动增量。但是,在这种情况下,它不会是标准的C / C ++文件。

A list of commands available: http://www.cppreference.com/wiki/preprocessor/start

可用命令列表:http://www.cppreference.com/wiki/preprocessor/start

#1


As others noted, __COUNTER__ is the easy but nonstandard way of doing this.

正如其他人所说,__ COUNTER__是这样做的简单但非标准的方式。

If you need extra portability, or for other cool preprocessor tricks, the Boost Preprocessor library (which works for C as well as C++) will work. For example, the following header file will output a unique label wherever it's included.

如果您需要额外的可移植性或其他很酷的预处理器技巧,Boost预处理器库(适用于C和C ++)将起作用。例如,以下头文件将在包含它的任何位置输出唯一标签。

#include <boost/preprocessor/arithmetic/inc.hpp>
#include <boost/preprocessor/slot/slot.hpp>

#if !defined(UNIQUE_LABEL)
#define UNIQUE_LABEL
#define BOOST_PP_VALUE 1
#include BOOST_PP_ASSIGN_SLOT(1)
#undef BOOST_PP_VALUE
#else
#define BOOST_PP_VALUE BOOST_PP_INC(BOOST_PP_SLOT(1))
#include BOOST_PP_ASSIGN_SLOT(1)
#undef BOOST_PP_VALUE
#endif


BOOST_PP_CAT(my_cool_label_, BOOST_PP_SLOT(1)):

Sample:

int main(int argc, char *argv[]) {
    #include "unique_label.h"
    printf("%x\n", 1234);
    #include "unique_label.h"
    printf("%x\n", 1234);
    #include "unique_label.h"
    return 0;
}

preprocesses to

int main(int argc, char *argv[]) {
    my_cool_label_1:
    printf("%x\n", 1234);
    my_cool_label_2:
    printf("%x\n", 1234);
    my_cool_label_3:
    return 0;
}

#2


If you're using GCC or MSVC, there is __COUNTER__.

如果您使用的是GCC或MSVC,则有__COUNTER__。

Other than that, you could do something vomit-worthy, like:

除此之外,你可以做一些呕吐物,比如:

#ifndef USED_1
#define USED_1
1
#else
#ifndef USED_2
#define USED_2
2
/* many many more */
#endif
#endif

#3


I use this:

我用这个:

#define MERGE_(a,b)  a##b
#define LABEL_(a) MERGE_(unique_name_, a)
#define UNIQUE_NAME LABEL_(__LINE__)

int main()
{
    int UNIQUE_NAME = 1;
    return 0;
}

... and get the following:

...并获得以下内容:

int main()
{
    int unique_name_8 = 1;
    return 0;
}

#4


I can't think of a way to automatically generate them but you could pass a parameter to MAKE_LABEL:

我想不出自动生成它们的方法,但您可以将参数传递给MAKE_LABEL:

#define MAKE_LABEL(n) my_cool_label_##n:

Then...

MAKE_FUNNY_JUMPING_LOOP(
  MAKE_LABEL(0);
  MAKE_LABEL(1);
)

#5


You could do this:

你可以这样做:

#define MAKE_LABEL() \
do {                 \   
my_cool_label:       \
/* some stuff */;    \
goto my_cool_label;  \
/* other stuff */;   \
} while (0) 

This keeps the scope of the label local, allowing any number of them inside the primary macro.

这使标签的范围保持在本地,允许在主宏中包含任意数量的标签。

If you want the labels to be accessed more globally, it's not clear how your macro "MAKE_FUNNY_JUMPING_LOOP" references these labels. Can you explain?

如果您希望更全面地访问标签,则不清楚宏“MAKE_FUNNY_JUMPING_LOOP”如何引用这些标签。你可以解释吗?

#6


It doesn't seem possible with a standard preprocessor, although you could fake it out by putting parameters within MAKE_LABEL or MAKE_FUNNY_JUMPING_LOOP, and use token pasting to create the label.

使用标准预处理器似乎不太可能,尽管您可以通过在MAKE_LABEL或MAKE_FUNNY_JUMPING_LOOP中放置参数来伪造它,并使用标记粘贴来创建标签。

There's nothing preventing you from making your own preprocessing script that does the automatic increment for you. However, it won't be a standard C/C++ file in that case.

没有什么可以阻止您制作自己的预处理脚本来为您自动增量。但是,在这种情况下,它不会是标准的C / C ++文件。

A list of commands available: http://www.cppreference.com/wiki/preprocessor/start

可用命令列表:http://www.cppreference.com/wiki/preprocessor/start