命名全局范围的丢弃标识符

时间:2010-08-12 16:08:40

标签: c++ c c-preprocessor naming

有时,当使用宏来生成代码时,有必要创建具有全局范围的标识符,但这些标识符对于创建它们的直接上下文之外的任何内容都没有用。例如,假设有必要将数组或其他索引资源编译时分配到各种大小的块中。

/* Produce an enumeration of some story-book characters, and allocate some
   arbitrary index resource to them.  Both enumeration and resource indices
   will start at zero.

   For each name, defines HPID_xxxx to be the enumeration of that name.
   Also defines HP_ID_COUNT to be the total number of names, and
   HP_TOTAL_SIZE to be the total resource requirement, and creates an
   array hp_starts[HP_ID_COUNT+1].  Each character n is allocated resources
   from hp_starts[n] through (but not including) hp_starts[n+1].
*/

/* Give the names and their respective lengths */
#define HP_LIST \
  HP_ITEM(FRED, 4) \
  HP_ITEM(GEORGE, 6) \
  HP_ITEM(HARRY, 5) \
  HP_ITEM(RON, 3) \
  HP_ITEM(HERMIONE, 8) \
  /* BLANK LINE REQUIRED TO ABSORB LAST BACKSLASH */

#define HP_ITEM(name, length) HPID_##name,
typedef enum { HP_LIST HP_ID_COUNT} HP_ID;
#undef HP_ITEM

#define HP_ITEM(name, length) ZZQ_##name}; enum {ZZQX_##name=ZZQ_##name+(length)-1,
enum { HP_LIST HP_TOTAL_SIZE};
#undef HP_ITEM

#define HP_ITEM(name, length) ZZQ_##name,
const unsigned char hp_starts[] = { HP_LIST HP_TOTAL_SIZE};
#undef HP_ITEM

#include "stdio.h"

void main(void)
{
  int i;

  printf("ID count=%d Total size=%d\n",HP_ID_COUNT,HP_TOTAL_SIZE);
  for (i=0; HP_ID_COUNT > i; i++) /* Reverse conditional to avoid lt sign */
    printf("  %2d=%3d/%3d\n", i, hp_starts[i], hp_starts[i+1]-hp_starts[i]);
  printf("IDs are: \n");
#define HP_ITEM(name, length) printf("  %2d=%s\n",HPID_##name, #name);
  HP_LIST
#undef HP_ITEMS

}

是否存在命名此类标识符的常规约定,以最大限度地减少冲突的可能性,并最大限度地减少它们可能产生的混淆?在上面的场景中,标识符ZZQ_xxx将与hp_starts [HPID_xxx]相同,并且在某些上下文中可能有用,尽管它们的主要目的是构建阵列并在计算其他ZZQ值和HP_TOTAL_SIZE时用作占位符。然而,标识符ZZQX_xxx是无用的;它们的唯一目的是在为后续项设置枚举值时用作占位符。有没有什么好方法来命名这些东西?

顺便说一句,我为小型微控制器开发的RAM比代码空间更高。通过在Microsoft VC ++上编译来模拟代码,但是对于生产是使用直接C中的交叉编译器编译的。因此,代码必须在C和C ++中编译。

是否还有人可以为类似任务推荐的其他预处理技巧?

2 个答案:

答案 0 :(得分:1)

  

是否存在命名此类标识符的常规约定,以最大限度地减少冲突的可能性,并最大限度地减少它们可能产生的混淆?

这一切都归结为你想要使用的前缀。理想情况下,人们希望所有符号都能与他们所关联的列表(HP_LIST)轻松关联。

那么为什么不将符号放在相同的HP_前缀下呢?例如。前缀HP__ZZQX_,用于区分有用符号和无用符号。

N.B。我参与过一个项目,其中一个共享库已经在使用(内部)zzqx_前缀,它总是出现在应用程序的符号表中。在不太可能使用的名称的竞争中,显然许多人采用相同的路线(拉丁字母的结尾)并最终得到完全相同的名称。与期望结果相反。这就是为什么我认为命名空间(或C中的符号前缀)不应该隐藏/隐藏在定义中,而是明确定义(例如易于查找和提取)。

作为具体的东西,这里是使用hack around ##增强的源代码,使用作为预处理器定义的前缀生成名称:


/* the hack is needed to force the LIST_NAME to be expanded. 
   automatically adds underscores. yes, it's ugly */
#define LIST_SYMBOL_1(n1,n2,n3) n1##_##n2##_##n3
#define LIST_SYMBOL_0(n1,n2,n3) LIST_SYMBOL_1(n1,n2,n3)
#define LIST_SYMBOL(pref,name)  LIST_SYMBOL_0(LIST_NAME,pref,name)

/* give the name to the list. used by the LIST_SYMBOL(). */
#define LIST_NAME   HP

/* Give the names and their respective lengths */
#define HP_LIST \
  HP_ITEM(FRED, 4) \
  HP_ITEM(GEORGE, 6) \
  HP_ITEM(HARRY, 5) \
  HP_ITEM(RON, 3) \
  HP_ITEM(HERMIONE, 8) \
  /* BLANK LINE REQUIRED TO ABSORB LAST BACKSLASH */

#define HP_ITEM(name, length) HPID_##name,
typedef enum { HP_LIST HP_ID_COUNT} HP_ID;
#undef HP_ITEM

#define HP_ITEM(name, length)   LIST_SYMBOL(ZZQ,name)}; \
    enum {LIST_SYMBOL(ZZQX,name)=LIST_SYMBOL(ZZQ,name)+(length)-1,
enum { HP_LIST HP_TOTAL_SIZE};
#undef HP_ITEM

#define HP_ITEM(name, length) LIST_SYMBOL(ZZQ,name),
const unsigned char hp_starts[] = { HP_LIST HP_TOTAL_SIZE};
#undef HP_ITEM

#include <stdio.h>

void main(void)
{
  int i;
  printf("ID count=%d Total size=%d\n",HP_ID_COUNT,HP_TOTAL_SIZE);
  for (i=0; i<HP_ID_COUNT ; i++) /* bring the < back, SO is smart enough */
    printf("  %2d=%3d/%3d\n", i, hp_starts[i], hp_starts[i+1]-hp_starts[i]);
  printf("IDs are: \n");
#define HP_ITEM(name, length) printf("  %2d=%s\n",HPID_##name, #name);
  HP_LIST
#undef HP_ITEMS
}

修改1 。我首选的方法是将数据放入适当的文本文件中,例如:

FRED
GEORGE
HARRY
RON
HERMIONE

(请注意,您不再需要长度)并编写一个脚本(甚至是一个简单的C程序)来从文本文件生成源代码,创建必要的头文件(使用enum +数据声明)和源代码文件(包含数据)。修改Makefile以在编译任何源之前运行脚本,并将生成的源文件添加到已编译源列表中。

具有巨大优势,即生成的代码是普通代码,并且可以这样编入索引(除非你喜欢“darn id来自哪里?”的乐趣)。由于脚本处理它们,因此内部常量在源代码中不再出现。并且没有任何虚假的预处理器魔法了。

答案 1 :(得分:0)

您可以检查boost项目中的预处理器宏。他们有聪明的预处理器计数器。与__LINE__一起,您可以使用它来生成唯一标识符,这些标识符仅取决于它们展开的行。这可以帮助您避免重新定义HP_ITEM宏。