2010-08-22 6 views
12

Für einige Basis. Basis 1 sogar. Eine Art von komplexer Substitution.Kann ich Nummern mit dem C/C++ - Präprozessor hinzufügen?

Auch, und natürlich, dies ist keine gute Idee in der realen Produktion Code. Ich habe nur aus Neugier gefragt.

+24

Sie werden nicht in der Lage sein, eine große Anzahl von Zahlen in Base 1 zu repräsentieren. – Artefacto

+3

Wir hätten niemals Base 1 verlassen sollen. Bits sind böse. –

+0

Basis 1 Addition ist einfach! Verketten Sie einfach die Makros/Makroargumente. – alternative

Antwort

10

Sie können relativ einfach Makro schreiben, die zwei Ganzzahlen in binär. Zum Beispiel - Makro, das zwei 4-Bit-Integer in binärer fasst:

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

Dieses Makro kann leicht für die Zugabe von zwei 8-Bit- oder 16-Bit oder sogar 32-Bit ints erweitert werden. Also im Grunde alles, was wir brauchen, ist Token Verkettung und Substitutionsregeln, um erstaunliche Ergebnisse mit Makros zu erzielen.

EDIT: Ich habe Formatierung der Ergebnisse geändert und noch wichtiger - ich habe Überlaufprüfung hinzugefügt.

HTH!

0

Ich bin ziemlich sicher, dass der C/C++ - Präprozessor nur kopieren und einfügen - es evaluiert tatsächlich keine Ausdrücke. Die Ausdruckauswertung wird vom Compiler durchgeführt.

Um Ihre Frage besser beantworten zu können, möchten Sie möglicherweise das posten, was Sie erreichen möchten.

+6

Der Präprozessor führt einige Ausdrücke aus. Die "# if" - und "# elif" -Direktiven nehmen Ausdrücke an, die durch einen Makro ersetzt werden müssen und dann ausgewertet werden, um zu bestimmen, ob sie wahr oder falsch (oder eins oder null in C) auswerten. –

5

Ich weiß, es ist nicht der Präprozessor, aber wenn es hilft, können Sie es mit Vorlagen tun. Vielleicht könnten Sie dies in Verbindung mit einem Makro verwenden, um das zu erreichen, was Sie brauchen.

#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

Warum nicht einfach 'Value = N + M' innerhalb von' Add' verwenden? –

+0

@James: Toller Punkt, danke. Ich habe meine Antwort aktualisiert. –

12

Der Präprozessor arbeitet auf Vorverarbeitung Token und das einzige Mal, dass es Zahlen wertet ist bei der Auswertung eines #if oder #elif Richtlinie. Ansonsten sind Zahlen während der Vorverarbeitung keine Zahlen. Sie sind als Vorverarbeitungsnummer Token klassifiziert, die nicht wirklich Zahlen sind.

könnten Sie bewerten Grundrechen Token Verkettung mit:

#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 

Wirklich, aber es gibt keinen Grund, dies zu tun, und es wäre dumm, dies zu tun (man müßte eine große Anzahl von definieren Makros, um auch nur entfernt nützlich zu sein).

Es wäre sinnvoller, ein Makro zu haben, die zu einem integralen konstanten Ausdruck erweitert, die vom Compiler ausgewertet werden kann:

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

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

Der Compiler in der Lage, die 1 + 1 Ausdruck auszuwerten.

+2

Ich sehe immer gerne, dass ## echte Arbeit leistet. – Tom

1

Der C-Präprozessor kann Bedingungen mit Ganzzahlarithmetik auswerten. Es wird keine arithmetischen Ausdrücke ersetzen und das Ergebnis dem Compiler übergeben, aber der Compiler wird Arithmetik auf Kompilierzeitkonstanten auswerten und das Ergebnis in das Binary ausgeben, solange Sie die verwendeten Operatoren nicht überladen haben.

1

Präprozessormakros können nicht wirklich arithmetisch arbeiten, aber sie können sinnvoll genutzt werden, um Berechnungen mit Aufzählungen durchzuführen. Der allgemeine Trick besteht darin, ein Makro zu haben, das andere Makros aufruft und wiederholt unter Verwendung anderer Definitionen dieser anderen Makros aufgerufen werden kann.

Zum Beispiel so etwas wie:

 
#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 

, dass man ‚zuweisen‘ eine bestimmte Menge an Speicherplatz für jede Sache in beispielsweise ermöglichen, eine Anordnung. Die Mathematik wird nicht vom Präprozessor ausgeführt, aber die Aufzählungen werden immer noch als Kompilierzeitkonstanten betrachtet.

3

Offenbar können Sie. Wenn Sie sich die Bibliothek Boost Preprocessor ansehen, können Sie mit dem Präprozessor alle möglichen Dinge tun, sogar die Ganzzahl addition.

+0

Der Boost Preprocessor hat (letztes Mal habe ich vor ein paar Jahren überprüft) die Spezifikationen nicht eingehalten.Das Additionsbit ist überhaupt nicht in der Spezifikation. – EML

+1

@EML - Ich spreche nicht von der Boost Wave-Bibliothek, die eine Implementierung eines C/C++ - Vorprozessors ist, den Sie in Ihrem Code verwenden können, sondern von der Boost Preprocessor-Bibliothek, die den bereits integrierten Preprozessor verwendet C/C++ Compiler, um einige erstaunliche Dinge zu tun. – Ferruccio

5

Es ist durchaus möglich, eine beschränkte ganzzahlige Addition im Präprozessor durchzuführen. Und es wird tatsächlich häufiger benötigt, als man wirklich hoffen würde, d. H. Die Alternative, nur ((2) + (3)) im Programm zu haben, funktioniert nicht. (Z. B. können Sie keine Variable x((2)+(3)) haben). Die Idee ist einfach: Drehen Sie die Addition in Inkremente, die Ihnen nichts ausmacht (zu viel), um sie alle aufzulisten. Z. B.

#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 

Jetzt wissen wir, wie zusätzlich zu tun, um bis zu 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 

hinzufügen Um noch größere Zahlen, müssen Sie irgendeine Art von „Rekursion“.

#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 

Man muss dabei aber vorsichtig sein. Zum Beispiel funktioniert das Folgende nicht.

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

Für jede erweiterte Verwendung solcher Tricks ist Boost Preprocessor Ihr Freund.