15

For some base. Base 1 even. Some sort of complex substitution -ing.

Also, and of course, doing this is not a good idea in real life production code. I just asked out of curiosity.

Lundin
  • 195,001
  • 40
  • 254
  • 396
user318904
  • 2,968
  • 4
  • 28
  • 37
  • 26
    You're not going to able to represent a lot of numbers in base 1. – Artefacto Aug 22 '10 at 00:11
  • 4
    We should never have left Base 1. bits are evil. – Camilo Martin Aug 22 '10 at 00:11
  • Base 1 addition is easy! Just concatenate the macros/macro arguments. – alternative Aug 22 '10 at 00:27
  • 2
    Um, base 1 is the same as a tally. 101 in base one is (1 * 1^3) + (0 * 1^2) + (1 * 1^1). – torak Aug 22 '10 at 00:27
  • 9
    @torak: Since when does base 1 have 2 digits? 101 is at least base two. – alternative Aug 22 '10 at 00:28
  • base 1 can only represent one number. – President James K. Polk Aug 22 '10 at 00:33
  • I think you'll need to clarify what you want to do. `#define SOMENUM (1 +3)` seems like addition to me, and it's definitely not what you meant to ask about. – Mhmmd Aug 22 '10 at 00:41
  • 11
    @GregS: base 1 might only have a single symbol, but it can represent any natural number (with the symbol repeated N times). http://en.wikipedia.org/wiki/Unary_numeral_system – Chris Schmich Aug 22 '10 at 00:43
  • so yeah, the base 1 was a sort of joke, I mentioned it cause you can do some trivial incrementing with base 1...but not the same as arbitrary addition. And ShaderOp, yeah I should have, that is about what I was thinking. – user318904 Aug 22 '10 at 23:20
  • Base 3 has 3 digits: 0, 1, and 2. Base 2 has two digits: 0 and 1. Logically, base 1 would only have one digit: 0. A simple tallying system, where 4 is `1111`, can be loosely referred to as "base 1", but it's not the same kind of representation. – Keith Thompson Sep 24 '11 at 20:09
  • base 1 can not represent 0 because 0 is a place holder. with base 1 you do not need a place holder. 101 = 2 = 11. 101 == 02. Leading zeros in a string mean nothing when you convert a string to a number. as an idea 2 is two and 0 is __ or the word zero. – RadioSpace Jun 12 '15 at 02:35
  • Possible duplicate: *[Can the C preprocessor perform integer arithmetic?](https://stackoverflow.com/questions/1560357/can-the-c-preprocessor-perform-integer-arithmetic)* – Peter Mortensen Aug 15 '23 at 13:53

8 Answers8

14

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.

James McNellis
  • 348,265
  • 75
  • 913
  • 977
14

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!

Agnius Vasiliauskas
  • 10,935
  • 5
  • 50
  • 70
7

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.

Isaac To
  • 71
  • 1
  • 2
5

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;
}
Chris Schmich
  • 29,128
  • 5
  • 77
  • 94
4

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.

Ferruccio
  • 98,941
  • 38
  • 226
  • 299
  • The Boost preprocessor has (last time I checked, a couple of years ago) poor compliance with the spec. The addition bit isn't in the spec at all. – EML May 22 '13 at 10:28
  • 2
    @EML - I'm not talking about the Boost Wave library, which is an implementation of a C/C++ pre-processor which you can use in your code, but rather the Boost Preprocessor library, which uses the preprocessor already built into your C/C++ compiler to do some amazing things. – Ferruccio Jan 27 '14 at 16:56
1

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.

Chris
  • 1,303
  • 8
  • 6
1

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.

supercat
  • 77,689
  • 9
  • 166
  • 211
0

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
greatwolf
  • 20,287
  • 13
  • 71
  • 105
  • 6
    The preprocessor does perform some expression evaluation. The `#if` and `#elif` directives both take expressions that must be macro replaced and then evaluated to determine whether they evaluate to true or false (or one or zero, in C). – James McNellis Aug 22 '10 at 00:31