【问题标题】:Can the C preprocessor perform integer arithmetic?C 预处理器可以执行整数运算吗?
【发布时间】:2010-12-06 07:57:09
【问题描述】:

正如问题所说,C 预处理器能做到吗?

例如:

#define PI 3.1416
#define OP PI/100
#define OP2 PI%100

有什么方法可以在预处理阶段计算 OP 和/或 OP2?

【问题讨论】:

  • 示例中的 PI 不是整数;因此,如果强制预处理器评估它们,则 OP 和 OP2 都不是整数。 '%' 的操作数不能是浮点数。

标签: c-preprocessor


【解决方案1】:

整数运算?运行以下程序找出:

#include "stdio.h"
int main() {
    #if 1 + 1 == 2
        printf("1+1==2\n");
    #endif
    #if 1 + 1 == 3
        printf("1+1==3\n");
    #endif
 }

答案是“是”,有一种方法可以让预处理器执行整数运算,即在预处理器条件下使用它。

但是请注意,您的示例不是整数算术。我刚刚检查过,如果你试图让它进行浮点比较,gcc 的预处理器会失败。我还没有检查标准是否允许在预处理器中进行浮点运算。

正则宏扩展不计算整数表达式,它将它留给编译器,通过预处理(gcc 中的 -E)可以看出:

#define ONEPLUSONE (1 + 1)
#if ONEPLUSONE == 2
    int i = ONEPLUSONE;
#endif

结果是int i = (1 + 1);(可能还有一些东西来表示源文件名和行号等)。

【讨论】:

  • Chris:我们现在生活在未来,虽然飞行汽车仍然不见踪影,但主函数的默认返回值已经到来!
  • @Chris:一个大括号,达到“返回值 0”(5.1.2.2.3,程序终止)。如果我不允许在标记为“C”的问题中假设标准 C,那么世界会变成什么?难道你不能找到在 C89 编译器可能看到的代码中使用 //-style cmets 的人,然后抱怨他们吗? ;-)
  • @Chris -- 右括号? :-)
  • 哦,不,我刚刚意识到克里斯的意思!由于 SO 格式化代码的方式,我的程序没有终止换行符!这甚至不是编译器必须诊断的无效程序,它是未定义的行为。恐怖、警报和普遍恐慌!我必须立即修复它。 ;-p
【解决方案2】:

您编写的代码实际上并没有让预处理器进行任何计算。 #define 进行简单的文本替换,因此定义如下:

#define PI 3.1416
#define OP PI/100

这段代码:

if (OP == x) { ... }

变成

if (3.1416/100 == x) { ... }

然后它被编译。反过来,编译器可能会选择采用这样的表达式并在编译时对其进行计算,并生成与此等效的代码:

if (0.031416 == x) { ... }

但这是编译器,而不是预处理器。

要回答您的问题,是的,预处理器可以做一些算术运算。当你写这样的东西时可以看到这一点:

#if (3.141/100 == 20)
   printf("yo");
#elif (3+3 == 6)
   printf("hey");
#endif

【讨论】:

  • 遗憾的是,如果您尝试条件编译 sn-p,您会收到来自 GCC 的消息:x.c:5:6: error: floating constant in preprocessor expression。您可以使用 C 预处理器进行整数运算;你不能用它做浮点运算。
  • 这里看起来像 gcc 偷工减料,Stroustrup C++ 2nd edition r.16.5 #if constant-expression, r.5.19 constant expression: "...浮动常量必须转换为整数类型"。
【解决方案3】:

是的,我的意思是:它可以做算术:)

99 bottles of beer 所示。

【讨论】:

    【解决方案4】:

    是的。

    我不敢相信还没有人与某个模糊的 C 竞赛获胜者相关联。这家伙通过递归包含在预处理器中实现了一个 ALU。 Here 是实现,here 是一种解释。

    现在,就是说,你不想做那个人做过的事。这很有趣,但请查看他的提示文件中的编译时间(更不用说生成的代码不可维护的事实)。更常见的是,人们将预处理器严格用于文本替换,而常量整数运算的评估发生在编译时或运行时。

    然而,正如其他人所指出的,您可以在 #if 语句中进行一些算术运算。

    【讨论】:

    【解决方案5】:

    是的,可以使用 Boost 预处理器来完成。它与纯 C 兼容,因此您可以在仅 C 编译的 C 程序中使用它。您的代码虽然涉及浮点数,所以我认为需要间接完成。

    #include <boost/preprocessor/arithmetic/div.hpp>
    BOOST_PP_DIV(11, 5) // expands to 2
    #define KB 1024
    #define HKB BOOST_PP_DIV(A,2)
    #define REM(A,B) BOOST_PP_SUB(A, BOOST_PP_MUL(B, BOOST_PP_DIV(A,B)))
    #define RKB REM(KB,2)
    
    int div = HKB;
    int rem = RKB;
    

    这会预处理到(使用 gcc -S 检查)

    int div = 512;
    int rem = 0;
    

    感谢this thread.

    【讨论】:

      【解决方案6】:

      算术时要小心:加括号

      #define SIZE4 4
      #define SIZE8 8
      #define TOTALSIZE SIZE4 + SIZE8
      

      如果你曾经使用过类似的东西:

      unsigned int i = TOTALSIZE/4;
      

      并期望 i 为 3,您将得到 4 + 2 = 6。 添加括号:

      #define TOTALSIZE (SIZE4 + SIZE8)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-17
        • 1970-01-01
        • 2011-03-24
        • 1970-01-01
        • 2021-09-20
        • 2011-04-02
        相关资源
        最近更新 更多