Frage

Ich bin mit BOOST_PP für precompile Berechnungen im Preprocessor zu tun. Konzentriere ich mich auf eine Anwendung, bei Codegröße ist extrem wichtig für mich. (Also bitte sagen Sie nicht, den Compiler sollte oder in der Regel das tut, muss ich kontrollieren, was bei der Kompilierung durchgeführt wird und welcher Code erzeugt wird). Ich möchte jedoch für beide Integer-Konstanten und Variablen den gleichen Namen des Makros / Funktion nutzen können. Als einfaches Beispiel kann ich

#define TWICE(n) BOOST_PP_MUL(n,2)
//.....
// somewhere else in code
int a = TWICE(5);

Das tut, was ich will, zu bewerten zu

int a = 10;

während der Kompilierung.

Allerdings möchte ich es auch verwendet werden

int b = 5;
int a = TWICE(b);

Dies sollte vorverarbeiteten zu

sein
int b = 5;
int a = 5 * 2;

Natürlich kann ich tun, indem sie die traditionellen Makros wie mit

#define TWICE(n) n * 2

Aber dann tut es das tun, was ich es für ganzzahlige Konstanten tun will (sie während der Kompilierung Auswertung).

Also, meine Frage ist, gibt es einen Trick, um zu überprüfen, ob das Argument eine wörtlichen oder eine Variable, und dann unterschiedliche Definitionen verwenden. das heißt, so etwas wie folgt aus:

#define TWICE(n) BOOST_PP_IF( _IS_CONSTANT(n), \
                              BOOST_PP_MUL(n,2), \
                              n * 2 )

edit: Also, was ich wirklich bin nach ist eine Möglichkeit, zu überprüfen, ob etwas eine Konstante zur Verfügung bei der Kompilierung ist und somit ein gutes Argument für die BOOST_PP_ Funktionen. Mir ist klar, dass dies anders aus, was die meisten Menschen von einem Prä-Prozessor und allgemeine Programmierempfehlungen erwarten. Aber es gibt keine falsch Art der Programmierung, also bitte nicht auf die Frage hassen, wenn Sie mit seiner Philosophie nicht einverstanden sind. Es gibt einen Grund die BOOST_PP Bibliothek vorhanden ist, und diese Frage ist im gleichen Sinne. Es könnte einfach nicht möglich, obwohl sein.

War es hilfreich?

Lösung

Sie versuchen, etwas zu tun, die besser auf die Optimierungen des Compilers verlassen wird.

int main (void) {
  int b = 5;
  int a = b * 2;

  return a; // return it so we use a and it's not optimized away
}

gcc O3 es T. C

 .file "t.c"
 .text
 .p2align 4,,15
.globl main
 .type main, @function
main:
.LFB0:
 .cfi_startproc
 movl $10, %eax
 ret
 .cfi_endproc
.LFE0:
 .size main, .-main
 .ident "GCC: (Debian 4.5.0-6) 4.5.1 20100617 (prerelease)"
 .section .note.GNU-stack,"",@progbits

Compiler Optimierung optimieren wird.

EDIT: Ich bin mir bewusst, dass Sie wollen nicht hören, dass der Compiler „sollte“ oder „in der Regel“ das tut. Doch zu tun, was Sie versuchen, ist nicht etwas, das in dem C-Präprozessor durchgeführt werden soll; die Menschen, die die C-Sprache und das C-Präprozessor entworfen entworfen es an der Arbeit mit der es ist, als basisches Atom Token Vorverarbeitung. Die CPP ist, in vielerlei Hinsicht, „stumm“. Das ist keine schlechte Sache (in der Tat ist dies in vielen Fällen, was es so nützlich macht), aber am Ende des Tages, es ist ein Präprozessor. Es vorverarbeitet Quelldateien, bevor sie analysiert werden. Es vorverarbeitet Quelldateien vor semantische Analyse auftritt. Es vorverarbeitet Quelldateien, bevor die Gültigkeit einer bestimmten Quelldatei überprüft wird. Ich verstehe, dass Sie nicht wollen, zu hören, dass dies etwas ist, dass der Parser und semantische Analysator behandeln soll oder in der Regel der Fall ist. Dies ist jedoch die Realität der Situation. Wenn Sie Code entwerfen möchten, die unglaublich klein ist, dann sollten Sie auf Ihrem Compiler verlassen seinen Job, anstatt zu versuchen Präprozessor Konstrukte zu tun, um zu schaffen, die Arbeit zu tun. Denken Sie daran, auf diese Weise: Tausende von Stunden Arbeit in Ihren Compiler gingen, so versuchen, so viel von dieser Arbeit wie möglich wieder zu verwenden

Andere Tipps

nicht ganz direkter Ansatz, aber:

struct operation {
    template<int N>
    struct compile {
        static const int value = N;
    };
    static int runtime(int N) { return N; }
};

operation::compile<5>::value;
operation::runtime(5);

alternativ

operation<5>();
operation(5);

Es gibt keine wirkliche Chance, Mischen der beiden Ebenen (Prä-Prozessor und Auswertung von Variablen ). Von dem, was ich von Ihnen Frage verstehen, b sollte eine symbolische Konstante sein?

ich glaube, Sie die traditionelle verwenden sollte

#define TWICE(n) ((n) * 2)

aber dann anstelle von Variablen mit Ausdrücken zu initialisieren, sollten Sie sie mit der Kompilierung Konstanten initialisiert werden. Das einzige, was ich sehe Auswertung bei der Kompilierung zu zwingen und symbolische Konstanten in C sind integrale Enumerationskonstanten zu haben. Diese sind definiert Typ int und sind bei der Kompilierung ausgewertet.

enum { bInit = 5 };
int b = bInit;
enum { aInit = TWICE(bInit) };
int a = aInit; 

Und in der Regel sollten Sie nicht zu sparsam sein mit const (wie für Ihre b) und prüfen Sie den erzeugten Assembler mit -S.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top