Подтвердить что ты не робот

Как я могу генерировать уникальные значения в препроцессоре C?

Я пишу кучу связанных макросов препроцессора, один из которых генерирует метки, к которым переходит другой. Я использую их следующим образом:

MAKE_FUNNY_JUMPING_LOOP(
  MAKE_LABEL();
  MAKE_LABEL();
)

Мне нужно каким-то образом генерировать уникальные ярлыки, по одному для каждого внутреннего вызова MAKE_LABEL, с препроцессором. Я пробовал использовать __LINE__, но поскольку я вызываю MAKE_LABEL внутри другого макроса, все они имеют одну и ту же строку, и метки сталкиваются.

Мне бы хотелось, чтобы это расширение было чем-то вроде:

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

Есть ли способ генерировать хэши или автоматически увеличивающиеся целые числа с препроцессором?

4b9b3361

Ответ 1

Как отмечали другие, __COUNTER__ - простой, но нестандартный способ сделать это.

Если вам нужна дополнительная переносимость или для других интересных трюков препроцессора, Boost Preprocessor library (которая работает как для 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)):

Пример:

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

препроцессы на

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

Если вы используете GCC или MSVC, есть __COUNTER__.

Кроме этого, вы могли бы сделать что-то рвотное, достойное, например:

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

Ответ 3

Я использую это:

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

... и получите следующее:

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

Ответ 4

Я не могу придумать способ их автоматического генерации, но вы можете передать параметр MAKE_LABEL:

#define MAKE_LABEL(n) my_cool_label_##n:

Тогда...

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

Ответ 5

Вы можете сделать это:

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

Это позволяет локализовать область метки, разрешая любое число из них внутри основного макроса.

Если вы хотите, чтобы метки были доступны более глобально, это не ясно, как ваш макрос "MAKE_FUNNY_JUMPING_LOOP" ссылается на эти метки. Можете ли вы объяснить?

Ответ 6

Это не представляется возможным при использовании стандартного препроцессора, хотя вы можете подделать его, поместив параметры в MAKE_LABEL или MAKE_FUNNY_JUMPING_LOOP, и используйте склейку для создания метки.

Ничего не мешает вам сделать свою собственную предварительную обработку script, которая делает автоматический приращение для вас. Однако в этом случае это не будет стандартный файл C/С++.

Список доступных команд: http://www.cppreference.com/wiki/preprocessor/start