Подтвердить что ты не робот

Можно ли добавить числа с препроцессором C/С++?

Для некоторой базы. База 1 ровная. Какая-то сложная замена.

Кроме того, и, конечно же, это не очень хорошая идея в коде жизненного цикла. Я просто спросил из любопытства.

4b9b3361

Ответ 1

Вы можете относительно легко писать макрос, который добавляет два целых числа в двоичном формате. Например - макрос, который суммирует два 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-битных int. Таким образом, в основном все, что нам нужно, это маркеры конкатенации и подстановки для достижения потрясающих результатов с помощью макросов.

EDIT: Я изменил формирование результатов и, что более важно, я добавил проверку переполнения.

НТН!

Ответ 2

Препроцессор работает с токенами предварительной обработки, и единственный раз, когда он оценивает числа, используется во время оценки директивы #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.

Ответ 3

Я знаю, что это не препроцессор, но если это помогает, вы можете сделать это с помощью шаблонов. Возможно, вы могли бы использовать это в сочетании с макросом для достижения того, что вам нужно.

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

Ответ 4

В препроцессоре вполне возможно сделать ограниченное целочисленное сложение. И это на самом деле требуется чаще, чем можно было бы надеяться, т.е. Альтернатива просто ((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 является вашим другом.

Ответ 5

Видимо, вы можете. Если вы посмотрите в библиотеке Boost Preprocessor, вы можете делать всевозможные вещи с препроцессором, даже целое число дополнение.

Ответ 6

Препроцессор C может оценивать условные обозначения, содержащие целочисленную арифметику. Он не будет заменять арифметические выражения и передавать результат компилятору, но компилятор будет оценивать арифметику на константах времени компиляции и выдавать результат в двоичный файл, если вы не перегружали используемых операторов.

Ответ 7

Макросы препроцессора не могут действительно выполнять арифметику, но они могут быть полезны для выполнения математики с перечислениями. Общий трюк состоит в том, чтобы иметь макрос, который вызывает другие макросы и может многократно вызываться с использованием разных определений этих других макросов.

Например, что-то вроде:

#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

Это позволит "распределить" определенное количество места для каждой вещи, например. массив. Математика не выполняется препроцессором, но перечисления по-прежнему рассматриваются как константы времени компиляции.

Ответ 8

Я уверен, что препроцессор C/С++ просто копирует и вставляет - он фактически не оценивает выражения. Оценка выражения выполняется компилятором.

Чтобы лучше ответить на ваш вопрос, вы можете опубликовать то, что вы пытаетесь выполнить.