2010-08-22 12 views
12

Per qualche base. Base 1 pari. Una sorta di sostituzione complessa.Posso aggiungere numeri con il preprocessore C/C++?

Inoltre, e ovviamente, farlo non è una buona idea nel codice di produzione della vita reale. Ho solo chiesto per curiosità.

+24

Non è possibile rappresentare molti numeri nella base 1. – Artefacto

+3

Non dovremmo mai aver lasciato la Base 1. I bit sono malvagi. –

+0

L'aggiunta di base 1 è facile! Basta concatenare gli argomenti macro/macro. – alternative

risposta

10

È possibile eseguire macro di scrittura relativamente semplice che aggiunge due numeri interi nello binario. Per esempio - macro che somma due interi a 4 bit in codice 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 
       ); 
} 

Questa macro può essere facilmente esteso per l'aggiunta di due int 8 bit o 16 bit o 32 bit. Quindi praticamente tutto ciò di cui abbiamo bisogno è la concatenazione di token e le regole di sostituzione per ottenere risultati sorprendenti con i macro.

MODIFICA: Ho cambiato la formazione dei risultati e, cosa più importante, ho aggiunto il controllo di overflow.

HTH!

0

Sono abbastanza sicuro che il preprocessore C/C++ faccia semplicemente copia e incolla, in realtà non valuta alcuna espressione. La valutazione dell'espressione viene eseguita dal compilatore.

Per rispondere meglio alla tua domanda, potresti pubblicare ciò che stai cercando di realizzare.

+6

Il preprocessore esegue una valutazione dell'espressione. Le direttive '# if' e' # elif' prendono entrambe le espressioni che devono essere sostituite da macro e quindi valutate per determinare se valutano true o false (o uno o zero, in C). –

5

So che non è il preprocessore, ma se aiuta, puoi farlo con i modelli. Forse potresti usarlo insieme a una macro per ottenere ciò di cui hai bisogno.

#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

Perché non usare solo "Valore = N + M" all'interno di "Aggiungi"? –

+0

@James: ottimo punto, grazie. Ho aggiornato la mia risposta. –

12

Il preprocessore opera su token pre-elaborazione e l'unica volta che valuta numeri è durante la valutazione di una direttiva o di #if#elif. Oltre a questo, i numeri non sono realmente numeri durante la pre-elaborazione; sono classificati come numero di preprocesso token, che in realtà non sono numeri.

Si potrebbe valutare l'aritmetica di base utilizzando la concatenazione 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 

In realtà, però, non c'è ragione per fare questo, e sarebbe stupido a farlo (che avrebbe dovuto definire un numero enorme di i macro per essere anche remotamente utili).

Sarebbe più sensato avere una macro che si espande per un'espressione costante intera che può essere valutata dal compilatore:

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

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

Il compilatore potrà valutare l'espressione 1 + 1.

+2

Mi piace sempre vedere il ## fare del vero lavoro. – Tom

1

Il preprocessore C può valutare condizionali contenenti aritmetica intera. Non sostituirà le espressioni aritmetiche e passerà il risultato al compilatore, ma il compilatore valuterà l'aritmetica sulle costanti in fase di compilazione ed emetterà il risultato nel file binario, purché non siano stati sovraccaricati gli operatori utilizzati.

1

Le macro di preprocessore non possono realmente fare aritmetica, ma possono essere utilmente sfruttate per fare matematica con le enumerazioni. Il trucco generale consiste nell'avere una macro che richiama altre macro e può essere ripetutamente invocata utilizzando definizioni diverse di quelle altre macro.

Per esempio, qualcosa come:

 
#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 

che permetterà uno a 'ripartire' una certa quantità di spazio per ogni cosa in es un array. La matematica non viene eseguita dal preprocessore, ma le enumerazioni sono ancora considerate come costanti in fase di compilazione.

3

Apparentemente, è possibile. Se dai un'occhiata alla libreria Boost Preprocessor, puoi fare qualsiasi cosa con il preprocessore, anche intero addition.

+0

Il preprocessore Boost ha (l'ultima volta che ho controllato, un paio di anni fa) una scarsa conformità con le specifiche.Il bit di addizione non è affatto nella specifica. – EML

+1

@EML - Non sto parlando della libreria Boost Wave, che è un'implementazione di un pre-processore C/C++ che puoi usare nel tuo codice, ma piuttosto della libreria Boost Preprocessor, che usa il preprocessore già integrato nel tuo Compilatore C/C++ per fare cose incredibili. – Ferruccio

5

È abbastanza possibile eseguire l'aggiunta di numeri limitati nel preprocessore. E, in realtà, è necessario più spesso di quanto si spera davvero, vale a dire, l'alternativa al solo ((2) + (3)) nel programma non funziona. (Ad esempio, non è possibile avere una variabile denominata x((2)+(3))). L'idea è semplice: trasforma l'aggiunta in incrementi, che non ti dispiace (troppo) elencandoli tutti. Per esempio,

#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 

Ora sappiamo come fare, oltre a un massimo di 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 

Per aggiungere numeri ancora più grandi, è necessario un qualche tipo di "ricorsione".

#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 

Tuttavia, bisogna fare attenzione. Ad esempio, quanto segue non funziona.

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

Per qualsiasi uso prolungato di tali trucchi, Preprocessore Boost è tuo amico.

Problemi correlati