如果你只有一个标识符

时间:2016-02-09 20:08:24

标签: c++ compiler-construction c-preprocessor

通常#define将用于定义常量或宏。但是,以下列方式使用#define是有效的代码。

#define MAX // does this do anything?
#define MAX 10 // I know how to treat this.

所以,如果我#define MAX 10,我知道我的预处理器用10替换MAX的所有实例。如果某人自己使用#define MAX但没有下面的替换值,那么它是有效的。这实际上做了什么吗?

我的理由是我在c ++中为c编写编译器并且需要处理预处理器指令但是我还没有能够找出在发生这种情况时是否需要具有任何功能或者一旦我的预处理完成,我就会忽略这一点。

我的第一直觉是,这会在我的符号表中创建一个没有名为MAX的值的符号,但同样可能它什么都不做。

作为一个问题的补充,我知道这种形式有点糟糕,但我真的很好奇。实际代码中是否存在使用此类内容的情况?

谢谢, Binx

5 个答案:

答案 0 :(得分:9)

典型的例子是标题保护:

#ifndef MYHEADER
#define MYHEADER
...
#endif

您可以使用#ifdef / ifndef来测试某些内容是否已定义。

答案 1 :(得分:7)

它创建一个带有空白定义的符号,以后可以在其他预处理器操作中使用。有几件事可以用于:

1)分支。

请考虑以下事项:

#define ARBITRARY_SYMBOL

// ...

#ifdef ARBITRARY_SYMBOL
    someCode();
#else   /* ARBITRARY_SYMBOL */
    someOtherCode();
#endif  /* ARBITRARY_SYMBOL */

符号的存在可用于分支,有选择地为情况选择适当的代码。很好地利用它是处理特定于平台的等效代码:

#if defined(_WIN32) || defined(_WIN64)
    windowsCode();
#elif defined(__unix__)
    unixCode();
#endif /* platform branching */

这也可以根据情况用于伪代码输出。例如,如果您想要一个仅在调试时存在的函数,您可能会有这样的事情:

#ifdef DEBUG
    return_type function(parameter_list) {
        function_body;
    }
#endif  /* DEBUG */

1A)头部守卫。

在上面的基础上,如果标题已经包含在跨越多个源文件的项目中,那么标题保护是一种dummying out整个标题的方法。

#ifndef HEADER_GUARD
#define HEADER_GUARD

// Header...

#endif  /* HEADER_GUARD */

2)贬低一个符号。

当与分支结合使用时,您还可以使用带有空白定义的定义来伪造符号。请考虑以下事项:

#ifdef _WIN32
    #define STDCALL __stdcall
    #define CDECL __cdecl
    // etc.
#elif defined(__unix__)
    #define STDCALL
    #define CDECL
#endif  /* platform-specific */

// ...

void CDECL cdeclFunc(int, int, char, const std::string&, bool);
// Compiles as void __cdecl cdeclFunc(/* args */) on Windows.
// Compiles as void cdeclFunc(/* args */) on *nix.

执行此类操作可以编写与平台无关的代码,但可以在Windows平台上指定调用约定。 [请注意,标题windef.h执行此操作,将CDECLPASCALWINAPI定义为不支持它们的平台上的空白符号。]这也可以在其他情况下,只要你需要一个预处理器符号,只在某些条件下扩展到其他东西。

3)文档。

空白宏也可用于记录代码,因为预处理器可以将它们剥离出来。 Microsoft非常喜欢这种方法,在windef.h中使用它来处理Windows函数原型中经常出现的INOUT符号。

也可能有其他用途,但这些是我能想到的唯一用途。

答案 2 :(得分:2)

它不会“做”任何东西,因为它不会在代码行中添加任何东西

#define MAX

int x = 1 + 2; MAX // here MAX does nothing

但是空定义的作用是允许你有条件地做某些事情,比如

#ifdef DEBUG
  // do thing
#endif

类似地header guards使用宏的存在来指示文件是否已经包含在翻译单元中。

答案 3 :(得分:1)

#define执行字符替换。如果您没有给出任何值,那么标识符将替换为...... nothing。现在这看起来很奇怪。我们经常使用它来创建一个标识符,可以使用#ifdef#ifndef来检查其存在性。最常见的用途是所谓的"包含警卫"。

在您自己的预处理器实现中,我认为没有理由将此视为特殊情况。该行为与任何其他#define语句相同:

  1. 将符号/值对添加到符号表中。

  2. 每当符号出现时,请将其替换为其值。

  3. 最有可能的是,对于没有值的符号,第2步永远不会发生。但是,如果是,则只删除符号,因为它的值为空。

答案 4 :(得分:0)

C预处理器(CPP)为使用#define宏定义的所有变量创建定义表。当CPP通过代码时,它至少会对这些信息做两件事。

首先,它为已定义的宏执行令牌替换。

#define MAX(a,b)  (a > b) ? (a) : (b)
MAX(1,2); // becomes (1 > 2) ? (1) : (2);

其次,它允许使用其他预处理器宏搜索这些定义,例如#ifdef#ifndef#undef或CPP扩展名,如#if defined(MACRO_NAME)

这允许在值不重要的情况下灵活使用宏定义,但定义令牌的事实很重要。

这允许使用以下代码:

// DEBUG is never defined, so this code would
// get excluded when it reaches the compiler.

#ifdef DEBUG
// ... debug printing statements
#endif