是否在运行前由预处理器进行评估?

时间:2015-02-09 15:46:59

标签: c c-preprocessor

我已完成此代码,以便在运行时由预处理器对其进行评估。

#define setPinToPortBit(pin)\
    if (pin < 19) PORTD ## pin;\
    else if(pin>14) PORTB ## (pin-14)\
        else PORTC ## (pin - 8)

#define STATION1 setPinToPortBit(15)

有没有办法知道这个代码示例何时会被评估?

是否在预处理时对其进行评估,以便在编译之前,digitalWrite(STATION1, 1)或某些包含digitalWrite(PORTB1, 1)等ifs和elses的扩展内容会产生代码digitalWrite(if(15<19)....

4 个答案:

答案 0 :(得分:1)

假设你有一行

digitalWrite(STATION1, 1)

预处理器将把它变成(假设我仍然可以做数学):

digitalWrite(if (15 < 19) PORTD15; else if(15>14) PORTB1 else PORTC7)

现在,据我所知,这不会编译,因为ifvoid类型的语句,这意味着它不会产生值。为了使事情顺利,你需要做的就是

#define setPinToPortBit(pin) \
    pin < 19 \
        ? PORTD ## pin \
        : pin > 14 \
            ? PORTB ## (pin-14) \
            : PORTC ## (pin - 8)

现在,预处理器会将该行转换为

digitalWrite(15<19 ? PORTD15 : 15>14 ? PORTB1 : PORTC7);

这是正确的C,如果PORTD15PORTB1PORTC7是具有相同静态类型的有效常量。

现在,C编译器将编译它。根据标准,编译器有权编译此代码,就好像它是

一样
digitalWrite(PORTD15);

但这不是强制性的:编译器可以根据它想要的任何东西来选择。

我经常看到的是,如果启用优化,所有体面的现代编译器都可以并且将预先评估这些常量条件。 如果未启用优化或者您正在调试模式下进行编译,那么我认为编译器将保持语句不变,而无需预先评估条件。因为您可能想要介入它们并通过调试器更改自然执行,然后您可能希望编译并使用该代码,即使它通常不会被执行。

当然,您可以通过反汇编可执行文件并进行分析来获得更准确的信息。

答案 1 :(得分:1)

在正确运行编译器之前,宏由预处理器进行扩展。

代码的扩展版本如下所示,

digitalWrite( if (15 < 19) PORTD15; else if(15>14) PORTB (15-14) else PORTC (15 - 8), 1)

您可以使用gcc -E file.c查看预处理的输出。它将在预处理阶段后停止。输出采用预处理源代码的形式,发送到标准输出。不需要预处理的输入文件将被忽略。

使用条件有三个一般原因。

  1. 程序可能需要使用不同的代码,具体取决于机器或 它是运行的操作系统。在某些情况下,代码为一个 操作系统在另一个操作系统上可能是错误的;对于 例如,它可能引用不存在的数据类型或常量 在另一个系统上。当发生这种情况时,这是不够的 执行无效代码。它的存在只会导致 编译器拒绝该程序。通过预处理条件, 当有时,可以从程序中有效地删除违规代码 这是无效的。
  2. 您可能希望能够将同一源文件编译为两个 不同的节目。一个版本可能经常耗费时间 一致性检查其中间数据,或打印的值 这些数据用于调试,而另一些则没有。
  3. 条件始终为false的条件是一种排除方式 该程序的代码,但将其作为一种评论,以备将来使用 参考
  4. 不需要系统特定逻辑或复杂调试挂钩的简单程序通常不需要使用预处理条件。

    条件指令是:

    #ifdef - If this macro is defined
    #ifndef - If this macro is not defined
    #if - Test if a compile time condition is true
    #else - The alternative for #if
    #elif - #else an #if in one statement
    #endif - End preprocessor conditional
    

    的示例:

      #ifdef DEBUG
        /* Your debugging statements here */
      #endif
    
    #if((NUM%2)==0)
          printf("\nNumber is Even");
    #else
          printf("\nNumber is Odd");
    #endif
    

答案 2 :(得分:0)

这取决于评估的含义。

预处理器通过代码扩展(换句话说,复制粘贴)定义。

常量和常量表达式的评估将在编译时完成。 if子句,如果转到if(true)或if(false)将在编译时进行评估,编译器可能会决定删除无法访问的代码。

如果你想要预处理器评估的if子句有#if,#elif或#else。

答案 3 :(得分:0)

如果您询问预处理器是否会对变量进行检查,然后为您应用正确的定义,则答案为 NO 。顺序是预处理器指令将被评估&amp;在编译器接受作业之前由预处理器替换,因此预处理器不知道正常变量的值是什么,并且无法为您进行检查。

预处理器将执行的操作是查找使用指令的位置,并将其替换为您的代码段。