我可以用C/C++预处理器加数字吗?

myss37ts  于 8个月前  发布在  C/C++
关注(0)|答案(8)|浏览(109)

一些基地。一号基地偶数。某种复杂的替代。
当然,在真实的生产代码中这样做也不是一个好主意。我只是好奇问一下。

yws3nbqq

yws3nbqq1#

你可以相对容易地编写宏,将两个整数以 * 二进制 * 相加。例如,- macro将两个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!

fsi0uk1n

fsi0uk1n2#

预处理器对预处理令牌进行操作,它唯一计算数字的时间是在#if#elif指令的计算期间。除此之外,在预处理过程中,数字并不是真正的数字;它们被归类为 * 预处理数字 * 标记,实际上不是数字。
你可以使用token concatenation来计算基本的算术:

#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表达式。

apeeds0o

apeeds0o3#

在预处理器中进行有界整数加法是完全可能的。而且,它实际上比人们真正希望的更经常地需要,即,在程序中只使用((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预处理器是您的朋友。

2fjabf4q

2fjabf4q4#

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

#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;
}
cunj1qz1

cunj1qz15#

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

wnrlj8wa

wnrlj8wa6#

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

qf9go6mv

qf9go6mv7#

预处理器宏实际上不能做算术运算,但可以有效地利用它们来进行枚举运算。一般的技巧是让一个宏调用其他宏,并且可以使用其他宏的不同定义重复调用。
例如,类似于:

#define MY_THINGS \
  a_thing(FRED,4) \
  a_thing(GEORGE,6) \
  a_thing(HARRY,5) \
  a_thing(HERMIONE,8) \
  a_thing(RON,3) \
  // This line left blank 

#define a_thing(name,size) EN_##name}; enum {EN_SIZE_##name=(size),EN_BLAH_##name = EN_##name+(size-1),
enum {EN_FIRST_THING=0, MY_THINGS EN_TOTAL_SIZE};
#undef a_thing

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

pzfprimi

pzfprimi8#

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

相关问题