2010-08-22 25 views
12

Para alguna base. Base 1 par. Algún tipo de sustitución compleja -ing.¿Puedo agregar números con el preprocesador C/C++?

Además, y por supuesto, hacer esto no es una buena idea en el código de producción de la vida real. Solo pregunte por curiosidad.

+24

No podrá representar una gran cantidad de números en la base 1. – Artefacto

+3

Nunca deberíamos haber salido de la Base 1. los bits son malos. –

+0

¡Además de la base 1 es fácil! Simplemente concatene los macros/argumentos de macro. – alternative

Respuesta

10

Puede escribir macro de manera relativamente fácil, lo que agrega dos enteros en binario. Por ejemplo - macro que resume dos enteros de 4 bits en binario:

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

Esta macro se puede ampliar fácilmente para la adición de dos enteros de 8 bits o de 16 bits, o incluso de 32 bits. Así que, básicamente, todo lo que necesitamos son reglas de concatenación y sustitución de tokens para lograr resultados asombrosos con las macros.

EDIT: He cambiado el formato de los resultados y, lo que es más importante, he agregado el control de desbordamiento.

HTH!

0

Estoy bastante seguro de que el preprocesador C/C++ solo copia y pega, en realidad no evalúa ninguna expresión. La evaluación de la expresión es realizada por el compilador.

Para responder mejor a su pregunta, es posible que desee publicar lo que está tratando de lograr.

+6

El preprocesador realiza alguna evaluación de expresión. Las directivas '# if' y' # elif' toman expresiones que deben ser reemplazadas por macro y luego evaluadas para determinar si se evalúan como verdaderas o falsas (o una o cero, en C). –

5

Sé que no es el preprocesador, pero si ayuda, puede hacerlo con plantillas. Tal vez podrías usar esto junto con una macro para lograr lo que necesitas.

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

¿Por qué no usar 'Value = N + M' dentro de' Add'? –

+0

@James: gran punto, gracias. He actualizado mi respuesta. –

12

El preprocesador funciona con fichas de pre-procesamiento y la única vez que se evalúa números es durante la evaluación de una directiva #if o #elif. Aparte de eso, los números no son realmente números durante el preprocesamiento; se clasifican como número de preprocesamiento tokens, que en realidad no son números.

Se puede evaluar la aritmética básica utilizando concatenación token:

#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 

Realmente, sin embargo, no hay razón para hacer esto, y sería tonto para hacerlo (que tendría que definir un gran número de macros para que sea remotamente útil).

Sería más sensato tener una macro que se expande a una expresión constante integral que puede ser evaluada por el compilador:

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

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

El compilador será capaz de evaluar la expresión 1 + 1.

+2

Siempre me gusta ver el ## haciendo un trabajo real. – Tom

1

El preprocesador C puede evaluar los condicionales que contienen la aritmética de enteros. No sustituirá expresiones aritméticas y pasará el resultado al compilador, pero el compilador evaluará la aritmética en constantes de tiempo de compilación y emitirá el resultado en el binario, siempre que no haya sobrecargado los operadores que se están utilizando.

1

Las macros de preprocesador no pueden realmente hacer aritmética, pero se pueden aprovechar para hacer cálculos matemáticos con enumeraciones. El truco general es tener una macro que invoca otras macros, y se puede invocar repetidamente utilizando diferentes definiciones de esas otras macros.

Por ejemplo, algo como:

 
#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 

Eso le permitirá a uno 'asignar' una cierta cantidad de espacio para cada cosa en, por ejemplo, una matriz. El preprocesador no realiza las operaciones matemáticas, pero las enumeraciones todavía se consideran como constantes de tiempo de compilación.

3

Aparentemente, usted puede. Si echa un vistazo a la biblioteca Boost Preprocessor, puede hacer todo tipo de cosas con el preprocesador, incluso el número entero addition.

+0

El preprocesador de Boost (la última vez que lo comprobé, hace un par de años) no cumple con la especificación.El bit de adición no está en la especificación en absoluto. – EML

+1

@EML - No estoy hablando de la biblioteca Boost Wave, que es una implementación de un preprocesador C/C++ que puede usar en su código, sino la biblioteca Boost Preprocessor, que usa el preprocesador ya integrado en su Compilador C/C++ para hacer cosas increíbles. – Ferruccio

5

Es muy posible hacer adiciones de números enteros acotados en el preprocesador. Y, en realidad, se necesita con más frecuencia de lo que uno realmente esperaría, es decir, la alternativa para simplemente tener ((2) + (3)) en el programa no funciona. (Por ejemplo, no puede tener una variable llamada x((2)+(3))). La idea es simple: convierta la suma en incrementos, lo cual no le molesta (demasiado) enumerarlos todos. Por ejemplo,

#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 

Ahora sabemos cómo hacerlo, además de hasta 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 

Para añadir números a aún más grandes, se necesita algún tipo de "recursividad".

#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 

Hay que tener cuidado con esto, sin embargo. Por ejemplo, lo siguiente no funciona.

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

Para cualquier uso prolongado de tales trucos, Boost Preprocessor es su amigo.

Cuestiones relacionadas