【问题标题】:Can I add numbers with the C/C++ preprocessor?我可以使用 C/C++ 预处理器添加数字吗?
【发布时间】:2011-04-02 03:48:28
【问题描述】:

对于一些基地。基数 1 偶数。某种复杂的替换。

当然,在现实生活中的生产代码中这样做并不是一个好主意。我只是出于好奇而问。

【问题讨论】:

  • 您无法以 1 为基数表示很多数字。
  • 我们不应该离开 Base 1。比特是邪恶的。
  • 嗯,base 1 与计数相同。以 1 为底的 101 为 (1 * 1^3) + (0 * 1^2) + (1 * 1^1)。
  • @torak:从什么时候开始以 1 为底有 2 位数字? 101 至少是基数二。
  • @GregS:base 1 可能只有一个符号,但它可以表示任何自然数(符号重复 N 次)。 en.wikipedia.org/wiki/Unary_numeral_system

标签: c++ c metaprogramming preprocessor


【解决方案1】:

我很确定 C/C++ 预处理器只是复制和粘贴——它实际上并不计算任何表达式。表达式评估由编译器完成。

为了更好地回答您的问题,您可能希望发布您想要完成的内容。

【讨论】:

  • 预处理器确实执行了一些表达式评估。 #if#elif 指令都采用必须被宏替换然后评估以确定它们评估为真或假(或一或零,在 C 中)的表达式。
【解决方案2】:

我知道这不是预处理器,但如果有帮助,您可以使用模板来完成。也许您可以将它与宏结合使用来实现您所需要的。

#include <iostream>
using namespace std;

template <int N, int M>
struct Add
{
    static const int Value = N + M;
};

int main()
{
    cout << Add<4, 5>::Value << endl;
    return 0;
}

【讨论】:

  • 为什么不在Add 内部使用Value = N + M
【解决方案3】:

预处理器对预处理标记进行操作,它评估数字的唯一时间是在评估#if#elif 指令期间。除此之外,在预处理过程中数字并不是真正的数字。它们被归类为 预处理数字 标记,它们实际上不是数字。

您可以使用标记连接来评估基本算术:

#define ADD_0_0 0
#define ADD_0_1 1
#define ADD_1_0 1
#define ADD_1_1 2

#define ADD(x, y) ADD##_##x##_##y

ADD(1, 0) // expands to 1
ADD(1, 1) // expands to 2

不过,实际上,没有理由这样做,而且这样做很愚蠢(您必须定义大量宏才能使其远程有用)。

将宏扩展为可由编译器计算的整数常量表达式会更明智:

#define ADD(x, y) ((x) + (y))

ADD(1, 1) // expands to ((1) + (1))

编译器将能够计算 1 + 1 表达式。

【讨论】:

    【解决方案4】:

    C 预处理器可以评估包含整数算术的条件。它不会替换算术表达式并将结果传递给编译器,但只要您没有重载正在使用的运算符,编译器就会对编译时常量进行算术运算并将结果发送到二进制文件中。

    【讨论】:

      【解决方案5】:

      预处理器宏不能真正进行算术运算,但可以有效地利用它们通过枚举进行数学运算。一般的技巧是拥有一个调用其他宏的宏,并且可以使用这些其他宏的不同定义重复调用。

      例如:

      #定义我的东西\ 一个东西(弗雷德,4)\ 一个东西(乔治,6)\ 一件事(哈利,5)\ 一个东西(赫敏,8)\ 一个东西(RON,3)\ // 此行留空 #define a_thing(name,size) EN_##name};枚举 {EN_SIZE_##name=(size),EN_BLAH_##name = EN_##name+(size-1), 枚举 {EN_FIRST_THING=0, MY_THINGS EN_TOTAL_SIZE}; #undef a_thing

      这将允许一个人为每个事物“分配”一定数量的空间,例如数组。数学运算不是由预处理器完成的,但枚举仍然被视为编译时常量。

      【讨论】:

        【解决方案6】:

        您可以相对容易地编写在二进制中添加两个整数的宏。例如 - 将两个 4 位整数二进制相加的宏:

        #include "stdio.h"
        
        // XOR truth table
        #define XOR_0_0 0
        #define XOR_0_1 1
        #define XOR_1_0 1
        #define XOR_1_1 0
        
        // OR truth table
        #define OR_0_0 0
        #define OR_0_1 1
        #define OR_1_0 1
        #define OR_1_1 1
        
        // AND truth table
        #define AND_0_0 0
        #define AND_0_1 0
        #define AND_1_0 0
        #define AND_1_1 1
        
        // concatenation macros
        #define XOR_X(x,y) XOR_##x##_##y
        #define   OR_X(x,y) OR_##x##_##y
        #define  AND_X(x,y) AND_##x##_##y
        #define OVERFLOW_X(rc1,rc2,rc3,rc4, rb1,rb2,rb3,rb4, a1,a2,a3,a4, b1,b2,b3,b4) OVERFLOW_##rc1 (rc1,rc2,rc3,rc4, rb1,rb2,rb3,rb4, a1,a2,a3,a4, b1,b2,b3,b4)
        
        // stringification macros
        #define STR_X(x) #x
        #define STR(x) STR_X(x)
        
        // boolean operators
        #define XOR(x,y) XOR_X(x,y)
        #define   OR(x,y) OR_X(x,y)
        #define  AND(x,y) AND_X(x,y)
        
        // carry_bit + bit1 + bit2
        #define BIT_SUM(carry,bit1,bit2) XOR(carry, XOR(bit1,bit2))
        // carry_bit + carry_bit_of(bit1 + bit2)
        #define CARRY_SUM(carry,bit1,bit2) OR(carry, AND(bit1,bit2))
        
        // do we have overflow or maybe result perfectly fits into 4 bits ?
        #define OVERFLOW_0(rc1,rc2,rc3,rc4, rb1,rb2,rb3,rb4, a1,a2,a3,a4, b1,b2,b3,b4) SHOW_RESULT(rc1,rc2,rc3,rc4, rb1,rb2,rb3,rb4, a1,a2,a3,a4, b1,b2,b3,b4)
        #define OVERFLOW_1(rc1,rc2,rc3,rc4, rb1,rb2,rb3,rb4, a1,a2,a3,a4, b1,b2,b3,b4) SHOW_OVERFLOW(rc1,rc2,rc3,rc4, rb1,rb2,rb3,rb4, a1,a2,a3,a4, b1,b2,b3,b4)
        
        // draft-horse macros which performs addition of two 4-bit integers
        #define ADD_BIN_NUM(a1,a2,a3,a4, b1,b2,b3,b4) ADD_BIN_NUM_4(0,0,0,0, 0,0,0,0, a1,a2,a3,a4, b1,b2,b3,b4)
        #define ADD_BIN_NUM_4(rc1,rc2,rc3,rc4, rb1,rb2,rb3,rb4, a1,a2,a3,a4, b1,b2,b3,b4) ADD_BIN_NUM_3(rc1,rc2,rc3,AND(CARRY_SUM(0,a4,b4),OR(a4,b4)), rb1,rb2,rb3,BIT_SUM(0,a4,b4), a1,a2,a3,a4, b1,b2,b3,b4)
        #define ADD_BIN_NUM_3(rc1,rc2,rc3,rc4, rb1,rb2,rb3,rb4, a1,a2,a3,a4, b1,b2,b3,b4) ADD_BIN_NUM_2(rc1,rc2,AND(CARRY_SUM(rc4,a3,b3),OR(a3,b3)),rc4, rb1,rb2,BIT_SUM(rc4,a3,b3),rb4, a1,a2,a3,a4, b1,b2,b3,b4)
        #define ADD_BIN_NUM_2(rc1,rc2,rc3,rc4, rb1,rb2,rb3,rb4, a1,a2,a3,a4, b1,b2,b3,b4) ADD_BIN_NUM_1(rc1,AND(CARRY_SUM(rc3,a2,b2),OR(a2,b2)),rc3,rc4, rb1,BIT_SUM(rc3,a2,b2),rb3,rb4, a1,a2,a3,a4, b1,b2,b3,b4)
        #define ADD_BIN_NUM_1(rc1,rc2,rc3,rc4, rb1,rb2,rb3,rb4, a1,a2,a3,a4, b1,b2,b3,b4)      OVERFLOW(AND(CARRY_SUM(rc2,a1,b1),OR(a1,b1)),rc2,rc3,rc4, BIT_SUM(rc2,a1,b1),rb2,rb3,rb4, a1,a2,a3,a4, b1,b2,b3,b4)
        #define OVERFLOW(rc1,rc2,rc3,rc4, rb1,rb2,rb3,rb4, a1,a2,a3,a4, b1,b2,b3,b4) OVERFLOW_X(rc1,rc2,rc3,rc4, rb1,rb2,rb3,rb4, a1,a2,a3,a4, b1,b2,b3,b4)
        #define   SHOW_RESULT(rc1,rc2,rc3,rc4, rb1,rb2,rb3,rb4, a1,a2,a3,a4, b1,b2,b3,b4) STR(a1) STR(a2) STR(a3) STR(a4) " + " STR(b1) STR(b2) STR(b3) STR(b4) " = " STR(rb1) STR(rb2) STR(rb3) STR(rb4)
        #define   SHOW_OVERFLOW(rc1,rc2,rc3,rc4, rb1,rb2,rb3,rb4, a1,a2,a3,a4, b1,b2,b3,b4) STR(a1) STR(a2) STR(a3) STR(a4) " + " STR(b1) STR(b2) STR(b3) STR(b4) " = overflow"
        
        void main()
        {
            printf("%s\n", 
                ADD_BIN_NUM(
                            0,0,0,1, // first  4-bit int
                            1,0,1,1) // second 4-bit int
                            );
        
            printf("%s\n", 
                ADD_BIN_NUM(
                            0,1,0,0, // first  4-bit int
                            0,1,0,1) // second 4-bit int
                        );
        
            printf("%s\n", 
                ADD_BIN_NUM(
                            1,0,1,1, // first  4-bit int
                            0,1,1,0) // second 4-bit int
                        );
        }
        

        这个宏可以很容易地扩展为添加两个 8 位或 16 位甚至 32 位整数。 因此,基本上我们所需要的只是令牌连接和替换规则,以使用宏实现惊人的结果。

        编辑: 我更改了结果的格式,更重要的是 - 我添加了溢出检查。

        HTH!

        【讨论】:

          【解决方案7】:

          显然,你可以。如果你看看Boost Preprocessor 库,你可以用预处理器做各种各样的事情,甚至是整数addition

          【讨论】:

          • Boost 预处理器(我上次检查,几年前)对规范的遵从性很差。添加位根本不在规范中。
          • @EML - 我不是在谈论 Boost Wave 库,它是可以在代码中使用的 C/C++ 预处理器的实现,而是 Boost 预处理器库,它使用 C/C++ 编译器中已经内置的预处理器来做一些令人惊奇的事情。
          【解决方案8】:

          很可能在预处理器中进行有界整数加法。而且,它实际上比人们真正希望的更频繁,即在程序中只包含((2) + (3)) 的替代方法不起作用。 (例如,您不能有一个名为 x((2)+(3)) 的变量)。这个想法很简单:将加法转换为增量,您不介意(太多)将它们全部列出。例如,

          #define INC(x) INC_ ## x
          #define INC_0 1
          #define INC_1 2
          #define INC_2 3
          #define INC_3 4
          #define INC_4 5
          #define INC_5 6
          #define INC_6 7
          #define INC_7 8
          #define INC_8 9
          #define INC_9 10
          INC(7) // => 8
          

          现在我们知道如何对最多 1 进行加法。

          #define ADD(x, y) ADD_ ## x(y)
          #define ADD_0(x) x
          #define ADD_1(x) INC(x)
          ADD(0, 2) // => 2
          ADD(1, 2) // => 3
          

          要添加到更大的数字,您需要某种“递归”。

          #define ADD_2(x) ADD_1(INC(x))
          #define ADD_3(x) ADD_2(INC(x))
          #define ADD_4(x) ADD_3(INC(x))
          #define ADD_5(x) ADD_4(INC(x))
          #define ADD_6(x) ADD_5(INC(x))
          #define ADD_7(x) ADD_6(INC(x))
          #define ADD_8(x) ADD_7(INC(x))
          #define ADD_9(x) ADD_8(INC(x))
          #define ADD_10(x) ADD_9(INC(x))
          ADD(5, 2) // => 7
          

          然而,在这方面必须小心。例如,以下行不通。

          #define ADD_2(x) INC(ADD_1(x))
          ADD(2, 2) // => INC_ADD_1(2)
          

          对于此类技巧的任何扩展使用,Boost Preprocessor 都是您的朋友。

          【讨论】:

            猜你喜欢
            • 2021-01-31
            • 2015-12-18
            • 1970-01-01
            • 1970-01-01
            • 2010-12-06
            • 2011-05-31
            • 2021-06-02
            • 2018-12-27
            • 1970-01-01
            相关资源
            最近更新 更多