Can I add numbers with the C/C++ preprocessor?
For some base. Base 1 even. Some sort of complex substitution -ing.
Also, and of course, doing this is not a good i开发者_如何学Cdea in real life production code. I just asked out of curiosity.
You can relatively easy write macro which adds two integers in binary. For example - macro which sums two 4-bit integers in binary :
#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
);
}
This macro can be easily extended for addition of two 8-bit or 16-bit or even 32-bit ints. So basically all that we need is token concatenation and substitution rules to achieve amazing results with macros.
EDIT: I have changed formating of results and more importantly - I've added overflow check.
HTH!
The preprocessor operates on preprocessing tokens and the only time that it evaluates numbers is during the evaluation of a #if
or #elif
directive. Other than that, numbers aren't really numbers during preprocessing; they are classified as preprocessing number tokens, which aren't actually numbers.
You could evaluate basic arithmetic using 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
Really, though, there's no reason to do this, and it would be silly to do so (you'd have to define a huge number of macros for it to be even remotely useful).
It would be more sensible to have a macro that expands to an integral constant expression that can be evaluated by the compiler:
#define ADD(x, y) ((x) + (y))
ADD(1, 1) // expands to ((1) + (1))
The compiler will be able to evaluate the 1 + 1
expression.
It is quite possible to do bounded integer addition in the preprocessor. And, it is actually needed more often than one would really hope, i.e., the alternative to just have ((2) + (3))
in the program doesn't work. (E.g., you can't have a variable called x((2)+(3))
). The idea is simple: turn the addition to increments, which you don't mind (too much) listing them all out. E.g.,
#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
Now we know how to do addition to up to 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
To add to even larger numbers, you need some sort of "recursion".
#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
One has to be careful in this, however. E.g., the following does not work.
#define ADD_2(x) INC(ADD_1(x))
ADD(2, 2) // => INC_ADD_1(2)
For any extended use of such tricks, Boost Preprocessor is your friend.
I know it's not the preprocessor, but if it helps, you can do it with templates. Perhaps you could use this in conjunction with a macro to achieve what you need.
#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;
}
Apparently, you can. If you take a look at the Boost Preprocessor library, you can do all sorts of stuff with the preprocessor, even integer addition.
The C preprocessor can evaluate conditionals containing integer arithmetic. It will not substitute arithmetic expressions and pass the result to the compiler, but the compiler will evaluate arithmetic on compile-time constants and emit the result into the binary, as long as you haven't overloaded the operators being used.
Preprocessor macros can't really do arithmetic, but they can be usefully leveraged to do math with enumerations. The general trick is to have a macro which invokes other macros, and can be repeatedly invoked using different definitions of those other macros.
For example, something like:
#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
That will allow one to 'allocate' a certain amount of space for each thing in e.g. an array. The math isn't done by the preprocessor, but the enumerations are still regarded as compile-time constants.
I'm pretty sure the C/C++ preprocessor just does copy and paste -- it doesn't actually evaluate any expressions. Expression evaluation is done by the compiler.
To better answer your question, you might want to post what you're trying to accomplish.
精彩评论