Wie funktioniert BOOST_BINARY()?
-
Hallo,
ich habe kürzlich in einem anderen Thread von BOOST_BINARY() gelesen. Es soll ja anscheinend die angegebene Binärzahl in ein Oktalliteral umwandeln. Ich hab mal in die Sourcen reingeschaut, aber die sehen sehr kompliziert aus. Kann mir jemand erklären, wie das vom Grundsatz her funktioniert? Das beißt sich nämlich mit meinen bisherigen Präprozessor-Kenntnissen, ich muss irgendeine Möglichkeit übersehen haben. Ähnlich geht es mir übrigens bei Qt mit Q_ENUM() oder wie das Makro heißt.
mfg
wxSkip
-
Geht es darum, wie genau er bei boost implementiert ist oder darum, wie man es umsetzen könnte (für Letzteres hätte ich eine Antwort)?
-
EOutOfResources schrieb:
Geht es darum, wie genau er bei boost implementiert ist oder darum, wie man es umsetzen könnte (für Letzteres hätte ich eine Antwort)?
Nur her damit

-
unsigned long int Binary(unsigned long int Bin) { std::stringstream BinStr; BinStr << Bin; std::bitset<sizeof(unsigned long int) * 8> Bits(BinStr.str()); return Bits.to_ulong(); }:p
-
Das Ganze ist mit der Brechstange auf Boost.Preprocessor aufgesetzt - du hast 256 Makros für die möglichen Werte eines Bytes, und wenn du in Boost.Preprocessor reinkuckst, wirst du feststellen, dass die ganzen Schleifenkonstrukte ganz ähnliche Mechanismen benutzen. Das kann man beispielsweise in boost/preprocessor/seq/fold_left.hpp wunderbar sehen - du kannst im Präprozessor keine echten Schleifen bauen, also baust du 256 durchnummerierte Makros, von denen eins sich jeweils auf das nächste bezieht.
Dabei wird ausgenutzt, dass man Makronamen in Makros wunderbar zusammensetzen kann. Beispiel:
#define PP_MACRO_1 foo #define PP_MACRO_2 bar #define PP_MACRO(x) PP_MACRO_ ## x ... PP_MACRO(1) // expandiert zu foo PP_MACRO(2) // expandiert zu barMit entsprechend großen Makrolisten kann man darauf aufsetzen, etwa
#define PP_LIST_1(m, x) m(x) #define PP_LIST_2(m, x, ...) m(x) PP_LIST_1(m, __VA_ARGS__) #define PP_LIST_3(m, x, ...) m(x) PP_LIST_2(m, __VA_ARGS__) ... #define PP_LIST(n, m, ...) PP_LIST_ ## n (m, __VA_ARGS__) PP_LIST(3, foo, bar, baz, qux) // expandiert zu foo(bar) foo(baz) foo(qux)In ähnlicher Weise kann man Makroaufrufe "rekursiv" gestalten, quasi als MACRO(x)(y)(z). Das krieg ich allerdings aus dem Stand nicht nachgebaut - du kannst es in boost/preprocessor/seq/elem.hpp einsehen. Auch da wird eine lange Liste von Makros, die zu anderen Makros expandieren, benutzt, so dass man sich der Reihe nach aus der Sequenz die einzelnen Elemente raussuchen und verarbeiten kann.
Um solche Tricks geht es da. Ich habe jetzt nicht die gesamte Boost.Preprocessor-Bibliothek im Detail studiert - die haben eine ganze Reihe lässiger Tricks auf diesen Ideen aufgebaut, die ich auch nicht alle durchschaue - aber letztendlich steckt da viel Fleißarbeit drin. Der Präprozessor gibt einem halt nicht viele Mittel in die Hand.
-
EOutOfResources schrieb:
unsigned long int Binary(unsigned long int Bin) { std::stringstream BinStr; BinStr << Bin; std::bitset<sizeof(unsigned long int) * 8> Bits(BinStr.str()); return Bits.to_ulong(); }:p
Na, da hab ich ja mit einem Makro und einem Berechen-Template schon eine bessere Lösung

Gut, diese Präprozessor-Maßnahmen habe ich schon einigermaßen gekannt, wenn ich jetzt aber eine Folge von z.B. 0100110011 einem Makro übergebe, was kann es groß damit anstellen? Man könnte einen String draus machen, das wird allerdings nicht direkt weiterhelfen. Ansonsten könnte man es mit einem vordefinierten Makronamen zusammenfügen - wie bei der Schleife. Allerdings bezweifle ich, dass Boost 2^32 Makronamen definiert hat. Leerzeichen innerhalb eines Arguments einzufügen ist ja per Makro nicht möglich, genausowenig wie Kommas, um es an ein anderes Makro zu übergeben. Wenn Leerzeichen zwischen Dreiergruppen von Nullen und Einsen wären, könnte man immerhin noch so etwas in der Art machen (dann halt wieder mit Schleifen):
#define BINARY_TOKEN001 1##BINARY( #define BINARY(arg) 0##BINARY_TOKEN##arg)
-
wxSkip schrieb:
Allerdings bezweifle ich, dass Boost 2^32 Makronamen definiert hat.
Nein hat es nicht. Die einzelnen Bitgruppen werden nur bis zur Länge 8 unterstützt, macht also nur 256 Makros. Dann noch für Länge 7, Länge 6 usw. ergibt etwas mehr als 500. Und das wurde tatsächlich gemacht -> Blick in die Source:
... #define BOOST_DETAIL_BINARY_LITERAL_ELEMENT_1110111 (1)(1)(1)(0)(1)(1)(1), #define BOOST_DETAIL_BINARY_LITERAL_ELEMENT_1111000 (1)(1)(1)(1)(0)(0)(0), #define BOOST_DETAIL_BINARY_LITERAL_ELEMENT_1111001 (1)(1)(1)(1)(0)(0)(1), #define BOOST_DETAIL_BINARY_LITERAL_ELEMENT_1111010 (1)(1)(1)(1)(0)(1)(0), #define BOOST_DETAIL_BINARY_LITERAL_ELEMENT_1111011 (1)(1)(1)(1)(0)(1)(1), #define BOOST_DETAIL_BINARY_LITERAL_ELEMENT_1111100 (1)(1)(1)(1)(1)(0)(0), #define BOOST_DETAIL_BINARY_LITERAL_ELEMENT_1111101 (1)(1)(1)(1)(1)(0)(1), #define BOOST_DETAIL_BINARY_LITERAL_ELEMENT_1111110 (1)(1)(1)(1)(1)(1)(0), #define BOOST_DETAIL_BINARY_LITERAL_ELEMENT_1111111 (1)(1)(1)(1)(1)(1)(1), #define BOOST_DETAIL_BINARY_LITERAL_ELEMENT_00000000 (0)(0)(0)(0)(0)(0)(0)(0), #define BOOST_DETAIL_BINARY_LITERAL_ELEMENT_00000001 (0)(0)(0)(0)(0)(0)(0)(1), #define BOOST_DETAIL_BINARY_LITERAL_ELEMENT_00000010 (0)(0)(0)(0)(0)(0)(1)(0), #define BOOST_DETAIL_BINARY_LITERAL_ELEMENT_00000011 (0)(0)(0)(0)(0)(0)(1)(1), #define BOOST_DETAIL_BINARY_LITERAL_ELEMENT_00000100 (0)(0)(0)(0)(0)(1)(0)(0), #define BOOST_DETAIL_BINARY_LITERAL_ELEMENT_00000101 (0)(0)(0)(0)(0)(1)(0)(1), ...Größere Zahlen kann bauen, indem man mehrere Gruppen durch Spaces trennt, z.B. entspricht
BOOST_BINARY(010 011101 1010011)der Zahl 01001110110100112. Wie jetzt aber die einzelnen Gruppen im Makro zusammengefügt werden, weiß ich jetzt auch nicht, das ist auch so ein Präprozessor-Trick.
-
Das erklärt natürlich vieles.
-
wxSkip schrieb:
ich habe kürzlich in einem anderen Thread von BOOST_BINARY() gelesen.
Hihi, der Hinweis war von mir.
Eigentlich steht doch, wie er funktioniert:
<pre><code>boost/utility/binary.hpp</code></pre> schrieb:
The following code works by converting the input bit pattern into a Boost.Preprocessor sequence, then converting groupings of 3 bits each into the corresponding octal digit, and finally concatenating all of the digits together along with a leading zero. This yields a standard octal literal with the desired value as specified in bits.
An unserem Beispiel:
010 011101 1010011 (0) (1) (0) (0) (1) (1) (1) (0) (1) (1) (0) (1) (0) (0) (1) (1) (0) (0) (4) (7) (3) (2) (3) 0047323Boost hat Makros geschrieben, mit denen man über die Argumente "iterieren" kann. Damit wird alles einfacher. Da werden je drei bit-Klammern in eine Okatale Zahl umgewandelt:
#define BOOST_DETAIL_TERNARY_TRIPLE_TO_OCTAL( bit2, bit1, bit0 ) \ BOOST_DETAIL_TRIPLE_TO_OCTAL_ ## bit2 ## bit1 ## bit0 #define BOOST_DETAIL_TRIPLE_TO_OCTAL_000 0 #define BOOST_DETAIL_TRIPLE_TO_OCTAL_001 1 #define BOOST_DETAIL_TRIPLE_TO_OCTAL_010 2 #define BOOST_DETAIL_TRIPLE_TO_OCTAL_011 3 #define BOOST_DETAIL_TRIPLE_TO_OCTAL_100 4 #define BOOST_DETAIL_TRIPLE_TO_OCTAL_101 5 #define BOOST_DETAIL_TRIPLE_TO_OCTAL_110 6 #define BOOST_DETAIL_TRIPLE_TO_OCTAL_111 7Kurz: das ganze ist eine mühsame Fleissarbeit.
-
Kenobi schrieb:
... Kurz: das ganze ist eine mühsame Fleissarbeit.
Vielleicht einen anderen Editor nehmen, gvim z.B....
-
abc.w schrieb:
Vielleicht einen anderen Editor nehmen, gvim z.B....
Mit Emacs kann man die Listen noch einfacher generieren lassen (Listt processing).
Aber ich zielte auf die nicht geposteten Schleifen ab.