Кто-нибудь знает, что это за определение декларации? - PullRequest
0 голосов
/ 05 февраля 2019

Я видел этот код в приложении, но я могу распознать, что такое синтаксис.я должен сделать эквивалент в C ++, но этот код в C. Кто-нибудь может помочь?вопрос в том, как сделать так, чтобы это запускалось в приложении на c ++?Как называется этот вид определения?это то же самое, что определяет каждую константу в списке?

/*! Object types */
#define F_ENUM(x, y) x = y,
#define F_SWITCH(x, y) case x: return ( #x );

#define OB_LIST(f) \
  f(T0, 0) \   //this declaration has no storage class or type specifier
               //identifier "T0" is undefined 
  f(T1, 1) \   //expected a ")"
               //unrecognized token  
               //expected a ";"
  f(T2, 2) \
  f(T3, 3) \
  f(T4, 4) \
  f(T5, 5)

enum mxt_object_type {
  OB_LIST(F_ENUM)
};

Более того, когда я компилирую это в компиляторе c ++, допускаю мои ошибки следующим образом: это объявление не имеет класса хранения или идентификатора спецификатора типа "T0"не определено ожидается ")" неопознанный токен ожидается ";"отмечено на коде.Кто-нибудь знает, почему ошибки ar ethis.

спасибо в продвинутом

Ответы [ 6 ]

0 голосов
/ 05 февраля 2019

Если вы добавите такой код

const char * enum2str(enum mxt_object_type type)
{
   switch(type) {
      OB_LIST(F_SWITCH)
   }
   return "invalid";
}

, вы получите функцию, которая переводит значения enum в строки без дублирования всех значений перечисления.Это полезно для вывода, например,

enum mxt_object_type type = T2;
printf("type is %s\n", enum2str(type));

Пример кода:

$ cat enum.c
/*! Object types */
#define F_ENUM(x, y) x = y,
#define F_SWITCH(x, y) case x: return ( #x );

#define OB_LIST(f) \
  f(T0, 0) \
  f(T1, 1) \
  f(T2, 2) \
  f(T3, 3) \
  f(T4, 4) \
  f(T5, 5)

enum mxt_object_type {
  OB_LIST(F_ENUM)
};

const char * enum2str(enum mxt_object_type type)
{
   switch(type) {
      OB_LIST(F_SWITCH)
   }
   return "invalid";
}

Выход препроцессора:

$ gcc -E enum.c
# 1 "enum.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "enum.c"
# 13 "enum.c"
enum mxt_object_type {
  T0 = 0, T1 = 1, T2 = 2, T3 = 3, T4 = 4, T5 = 5,
};

const char * enum2str(enum mxt_object_type type)
{
   switch(type) {
  case T0: return ( "T0" ); case T1: return ( "T1" ); case T2: return ( "T2" ); case T3: return ( "T3" ); case T4: return ( "T4" ); case T5: return ( "T5" );
   }
   return "invalid";
}
0 голосов
/ 05 февраля 2019

Это известно как «X macros», что означает создание списка констант любого вида и централизованное ведение этого списка в одном месте исходного кода, чтобы избежать повторения кода.За счет читабельности.

В этом случае OB_LIST, который, по-видимому, представляет собой список имен перечислений и их соответствующих значений.

Обычно это выглядит так (отсюда и название "X"macros "):

#define OB_LIST     \
/*  type  value  */ \
  X(T0,       0)    \
  X(T1,       1)    \
  X(T2,       2)    \
  X(T3,       3)    \
  X(T4,       4)    \
  X(T5,       5)    \

enum mxt_object_type {

  #define X(type, value) type = value,
    OB_LIST
  #undef X
};

Где type = value, - это то, что я хочу, чтобы каждая строка в моем объявлении enum была похожа.Когда макрос OB_LIST раскрывается, этот «макрос X» раскрывается для всех значений в списке с указанными значениями.

После предварительной обработки вы получаете:

enum mxt_object_type {
  T0 = 0,
  T1 = 1,
  ...
};

Затем вы можете написать похожие макросы X для каждого фрагмента кода, повторяя все эти значения.Думайте об этом как о способе циклического развертывания, но сделанного во время компиляции.


Человек, который написал ваш код, продвинул эту практику / обфускацию еще на один шаг, не объявляя макрос X локально, новместо этого централизуйте их и передайте конкретное поведение в список объектов.

Я бы не назвал это хорошей практикой, поскольку в результате вы получаете много странных макросов в заголовке где-то вне контекста.

0 голосов
/ 05 февраля 2019

Используется макроопределение для определения другого перечислимого типа.F_ENUM - это макрос, определяющий каждый элемент в enum.F_SWICH - это макрос, который будет использоваться в операторе switch.Этот метод используется для избежания дублирования кода

0 голосов
/ 05 февраля 2019

Ну, если вы предварительно обработаете этот код в файл, вы получите:

enum mxt_object_type {
  T0 = 0, T1 = 1, T2 = 2, T3 = 3, T4 = 4, T5 = 5,
};

Так что это набор макросов для создания enum с именами элементов T#.

0 голосов
/ 05 февраля 2019

Когда вы хотите увидеть результат после обработки, просто попросите его посмотреть, с gcc / g ++ , если у вас есть код, можно задать -Eрезультат:

pi@raspberrypi:/tmp $ gcc -E d.c
# 1 "d.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "d.c"
# 13 "d.c"
enum mxt_object_type {
  T0 = 0, T1 = 1, T2 = 2, T3 = 3, T4 = 4, T5 = 5,
};

Конечно, здесь F_SWITCH не используется

Я должен сделать эквивалент в C ++, но этот код находится в C

Вам нечем заняться, что делает то же самое в C ++

Эти макросы предназначены для препроцессора, а не для C или C ++, которые видят результат, который я показал в начале

Пример компиляции в C ++:

pi@raspberrypi:/tmp $ cat d.cc
/*! Object types */
#define F_ENUM(x, y) x = y,
#define F_SWITCH(x, y) case x: return ( #x );

#define OB_LIST(f) \
  f(T0, 0) \
  f(T1, 1) \
  f(T2, 2) \
  f(T3, 3) \
  f(T4, 4) \
  f(T5, 5)

enum mxt_object_type {
  OB_LIST(F_ENUM)
};
pi@raspberrypi:/tmp $ g++ -c -pedantic -Wall d.cc
pi@raspberrypi:/tmp $ 

Как это работает:

  • сначала в форме OB_LIST(F_ENUM) OB_LIST расширяется с получением F_ENUM(T0, 0) F_ENUM(T1, 1) F_ENUM(T2, 2) F_ENUM(T3, 3) F_ENUM(T4, 4) F_ENUM(T5, 5)
  • затем каждый F_ENUM расширяется, получая конечный результат T0 = 0, T1 = 1, T2 = 2, T3 = 3, T4 = 4, T5 = 5,

Классическое использование F_SWITCH:

const char * nameIt(mxt_object_type v)
{
  switch (v) {
    OB_LIST(F_SWITCH)
  default:
    return "unknown";
  }
}

, которое дает:

const char * nameIt(mxt_object_type v)
{
  switch (v) {
    case T0: return ( "T0" ); case T1: return ( "T1" ); case T2: return ( "T2" ); case T3: return ( "T3" ); case T4: return ( "T4" ); case T5: return ( "T5" );
  default:
    return "unknown";
  }
}

строки типа "T0" создаются #x, которые помещают x в буквальную строку после ее подстановки ее значением

0 голосов
/ 05 февраля 2019
enum mxt_object_type {
  T0 = 0,
  T1 = 1,
  T2 = 2,
  T3 = 3,
  T4 = 4,
  T5 = 5,
};

Попробуйте Google XMACRO

...