谁知道这个定义声明是什么?

时间:2019-02-05 14:43:51

标签: c c-preprocessor

我在应用程序中看到了此代码,但我可以识别出什么是正税。我必须在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”未定义 应该是“)” 无法识别的令牌 预期为“;” 在代码上标记。 任何人都知道为什么会出现此错误。

非常感谢

6 个答案:

答案 0 :(得分:4)

当您想查看处理后的结果是什么时,只需问一下即可,如果使用 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 替换为文字字符串,然后用其值替换

答案 1 :(得分:2)

这称为“ X宏”,它用于制作任何类型的常量列表并将该列表的维护集中到源代码中的单个位置,以避免代码重复。以可读性为代价。

在这种情况下,OB_LIST显然是枚举名称及其对应值的列表。

通常是这样的(因此命名为“ X宏”):

#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,一样。宏OB_LIST展开后,此“ X宏”将扩展为列表中所有指定值的值。

经过预处理后,您最终得到:

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

然后,您可以为重复所有这些值的每段代码编写类似的X宏。可以将其视为循环展开的一种方式,但可以在编译时完成。


编写代码的人通过不在本地声明X宏,而是对它们进行集中化并将特定行为传递到对象列表上,从而使这种做法/混淆进一步了。

我不会称其为良好做法,因为您最终会在头文件中的某个地方(从任何上下文中删除)都拥有许多奇怪的宏。

答案 2 :(得分:1)

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

尝试使用Google XMACRO

答案 3 :(得分:0)

好吧,如果将代码预处理到文件中,则会得到:

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

这是一组用于创建成员名称为enum的{​​{1}}的宏。

答案 4 :(得分:0)

它使用宏定义来定义另一个枚举类型。 F_ENUM是一个宏,用于定义枚举中的每个项目。 F_SWICH是将在switch语句中使用的宏。此技术用于避免重复代码

答案 5 :(得分:0)

如果您添加这样的代码

False

您将获得一个函数,该函数将defined的值转换为字符串,而无需复制所有枚举值。这对于输出很有用,例如

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