2013-03-29 7 views
6

In verschiedenen Low-Level-Teilen unseres Codes müssen wir bestimmte Bytes an ein Gerät senden, damit Dinge passieren können. Als solche haben wir viel Code, der wie folgt aussieht:Deklarieren von char hexadezimalen Konstanten in C++ 11

const char magic_bytes[] = { 0x01, 0xFA, 0x92 }; 

, die in dem Fehler führt (auf GCC 4.7.2)

test_char.cpp:6:51: warning: narrowing conversion of ‘250’ from ‘int’ to ‘const char’ inside { } is ill-formed in C++11 [-Wnarrowing] 

Da 0xFA außerhalb des Bereichs von -128 bis 127.

Es gibt zwei Lösungen, die ich mir vorstellen kann:

const char magic_bytes[] = { static_cast<char>(0x01), static_cast<char>(0xFA), static_cast<char>(0x92) }; 

oder:

012.351.
const unsigned char magic_bytes[] = { 0x01, 0xFA, 0x92 }; 

beide entweder hässlich (der erste Fall) sind, oder haben andere Nachteile (mit bis (const char *) in dem Fall des letzteren cast)

Gibt es eine bessere Art und Weise zu erklären, diese Saiten?

+4

da du technisch mit 'unsigned char's arbeitest, warum musst du nach' char' umwandeln? Es gibt nicht wirklich eine bessere Lösung, die Conversions mit Makros nicht zu verstecken. – Dave

+2

@Dave: Leider ist das universelle Symbol für "Array von Bytes" in C und C++ 'char *', nicht 'unsigned char *'. Deshalb brauchst du normalerweise die Besetzung. Ja, es sollte wirklich 'void *' sein, aber viele APIs nehmen 'char *' s stattdessen. –

Antwort

4

C++ 11 geben Sie variadic templates (mit GCC Unterstützung für einige Zeit existiert) Um dieses Problem zu lösen.

template <typename... A>                 
constexpr std::array<char, sizeof...(A)> byte_array(A... v)        
{ return std::array<char, sizeof...(A)>{{static_cast<char>(v)...}}; }      

constexpr auto arr = byte_array(0x01, 0xFA, 0x92); 

Oder wiederholt .data() bis C funcs für Leiten Aufruf zu vermeiden:

template <std::size_t S> 
struct byte_array { 
    char data_[S]; 
    char *data() { return data_; } 
    operator char*() { return data_; } 

    const char *data() const { return data_; } 
    operator const char*() const { return data_; } 

    constexpr std::size_t size() const { return S; } 

    // one could add support for begin/end and things like that 
}; 

template <typename... A> 
constexpr byte_array<sizeof...(A)> make_byte_array(A... v) 
{ return byte_array<sizeof...(A)>{{static_cast<char>(v)...}}; } 

// beside constexpr, this can be also non-const 
auto magic_bytes = make_byte_array(0x01, 0xFA, 0x92); 
strtok(magic_bytes, "why?"); 

Es gibt keinen Overhead in der Ebene char-Array zu vergleichen.

1

Sie etwas tun können einen Guss haben:

const unsigned char magic_bytesUC[] = { 0x01, 0xFA, 0x92 }; 
enum { NBYTES = sizeof(magic_bytesUC) }; 
const char *magic_bytes = reinterpret_cast<const char*>(magic_bytesUC); 
1

Da Sie C++ 11 angegeben, ich nehme an, Sie variadic macros verwenden können. In diesem Fall gibt es eine Lösung, die elegant ist, wenn sie verwendet wird, aber so hässlich wie sie hinter die Kulissen kommt.

Also ich zeigen Sie beginnen werde, wie Sie es verwenden würde:

char myBytes1[] = MAKE_BYTES(0x00, 0x40, 0x80, 0xC0); 
char myBytes2[] = MAKE_BYTES(0xFF); 

Und nun, den Back-End-Code: Dieser kürzer sein könnte, aber ich habe Standard-Looping Methoden verwendet, so dass Sie bekommen könnte einige wiederverwenden daraus. Es kann 1 - 24 Byte Listen unterstützen. Es kann größer gemacht werden, indem die letzten Zeilen noch einmal wiederholt werden. Willkommen in der Welt der Pre-Prozessor-Meta-Programmierung.

#define EXPAND(a) a 
#define ARGS_COUNT_(\ 
    _96,_95,_94,_93,_92,_91,_90,_89,_88,_87,_86,_85,_84,_83,_82,_81,\ 
    _80,_79,_78,_77,_76,_75,_74,_73,_72,_71,_70,_69,_68,_67,_66,_65,\ 
    _64,_63,_62,_61,_60,_59,_58,_57,_56,_55,_54,_53,_52,_51,_50,_49,\ 
    _48,_47,_46,_45,_44,_43,_42,_41,_40,_39,_38,_37,_36,_35,_34,_33,\ 
    _32,_31,_30,_29,_28,_27,_26,_25,_24,_23,_22,_21,_20,_19,_18,_17,\ 
    _16,_15,_14,_13,_12,_11,_10, _9, _8, _7, _6, _5, _4, _3, _2, _1,\ 
    N,...) N 
#define ARGS_COUNT(...) ARGS_COUNT_(__VA_ARGS__,\ 
    96,95,94,93,92,91,90,89,88,87,86,85,84,83,82,81,\ 
    80,79,78,77,76,75,74,73,72,71,70,69,68,67,66,65,\ 
    64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,\ 
    48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,\ 
    32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,\ 
    16,15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1) 
#define ARGS_HEAD(a,...) (a) 
#define ARGS_TAIL(a,...) (__VA_ARGS__) 

#define FOREACH(macro,lmacro,list) FOREACH_(ARGS_COUNT list,macro,lmacro,list) 
#define FOREACH_(n,macro,lmacro,list) FOREACH__(n,macro,lmacro,list) 
#define FOREACH__(n,macro,lmacro,list) FOREACH_##n(macro,lmacro,list) 
#define FOREACH_1(macro,lmacro,list) lmacro list 
#define FOREACH_2(macro,lmacro,list) EXPAND(macro ARGS_HEAD list) FOREACH_1(macro,lmacro,ARGS_TAIL list) 
#define FOREACH_3(macro,lmacro,list) EXPAND(macro ARGS_HEAD list) FOREACH_2(macro,lmacro,ARGS_TAIL list) 
#define FOREACH_4(macro,lmacro,list) EXPAND(macro ARGS_HEAD list) FOREACH_3(macro,lmacro,ARGS_TAIL list) 
#define FOREACH_5(macro,lmacro,list) EXPAND(macro ARGS_HEAD list) FOREACH_4(macro,lmacro,ARGS_TAIL list) 
#define FOREACH_6(macro,lmacro,list) EXPAND(macro ARGS_HEAD list) FOREACH_5(macro,lmacro,ARGS_TAIL list) 
#define FOREACH_7(macro,lmacro,list) EXPAND(macro ARGS_HEAD list) FOREACH_6(macro,lmacro,ARGS_TAIL list) 
#define FOREACH_8(macro,lmacro,list) EXPAND(macro ARGS_HEAD list) FOREACH_7(macro,lmacro,ARGS_TAIL list) 
#define FOREACH_9(macro,lmacro,list) EXPAND(macro ARGS_HEAD list) FOREACH_8(macro,lmacro,ARGS_TAIL list) 
#define FOREACH_10(macro,lmacro,list) EXPAND(macro ARGS_HEAD list) FOREACH_9(macro,lmacro,ARGS_TAIL list) 
#define FOREACH_11(macro,lmacro,list) EXPAND(macro ARGS_HEAD list) FOREACH_10(macro,lmacro,ARGS_TAIL list) 
#define FOREACH_12(macro,lmacro,list) EXPAND(macro ARGS_HEAD list) FOREACH_11(macro,lmacro,ARGS_TAIL list) 
#define FOREACH_13(macro,lmacro,list) EXPAND(macro ARGS_HEAD list) FOREACH_12(macro,lmacro,ARGS_TAIL list) 
#define FOREACH_14(macro,lmacro,list) EXPAND(macro ARGS_HEAD list) FOREACH_13(macro,lmacro,ARGS_TAIL list) 
#define FOREACH_15(macro,lmacro,list) EXPAND(macro ARGS_HEAD list) FOREACH_14(macro,lmacro,ARGS_TAIL list) 
#define FOREACH_16(macro,lmacro,list) EXPAND(macro ARGS_HEAD list) FOREACH_15(macro,lmacro,ARGS_TAIL list) 
#define FOREACH_17(macro,lmacro,list) EXPAND(macro ARGS_HEAD list) FOREACH_16(macro,lmacro,ARGS_TAIL list) 
#define FOREACH_18(macro,lmacro,list) EXPAND(macro ARGS_HEAD list) FOREACH_17(macro,lmacro,ARGS_TAIL list) 
#define FOREACH_19(macro,lmacro,list) EXPAND(macro ARGS_HEAD list) FOREACH_18(macro,lmacro,ARGS_TAIL list) 
#define FOREACH_20(macro,lmacro,list) EXPAND(macro ARGS_HEAD list) FOREACH_19(macro,lmacro,ARGS_TAIL list) 
#define FOREACH_21(macro,lmacro,list) EXPAND(macro ARGS_HEAD list) FOREACH_20(macro,lmacro,ARGS_TAIL list) 
#define FOREACH_22(macro,lmacro,list) EXPAND(macro ARGS_HEAD list) FOREACH_21(macro,lmacro,ARGS_TAIL list) 
#define FOREACH_23(macro,lmacro,list) EXPAND(macro ARGS_HEAD list) FOREACH_22(macro,lmacro,ARGS_TAIL list) 
#define FOREACH_24(macro,lmacro,list) EXPAND(macro ARGS_HEAD list) FOREACH_23(macro,lmacro,ARGS_TAIL list) 

#define MAKE_BYTE(x) static_cast<char>(x), 
#define MAKE_LAST_BYTE(x) static_cast<char>(x) 
//#define MAKE_BYTES(x) { FOREACH(MAKE_BYTE,MAKE_LAST_BYTE,x) } // uncomment this if you would rather use double bracket ((0x00,0x40,...)) syntax 
#define MAKE_BYTES(...) { FOREACH(MAKE_BYTE,MAKE_LAST_BYTE,(__VA_ARGS__)) } 
+0

Sind die Variadic-Makros abwärtskompatibel mit C++ 03? Oder, für uns akzeptabel, wurden sie als GCC-Erweiterung in früheren Versionen (etwa GCC 4.2) eingeführt? – Damien

+1

@Damien: Ja (eine GCC-Erweiterung), wenn Sie jedoch weit genug zurückgehen, ändert sich die Syntax in benannte Parameter mit 'nameOfArgs ...'. In meinen Projekten habe ich Checks, um die variadischen Makros zu tauschen (und ich benutze das kommentierte Formular aus den letzten Zeilen, um alle Änderungen in den gemeinsamen Bits zu behalten), aber das bedeutet offensichtlich viel mehr Code. Das Problem ist, dass dies bis C99 und C++ 11 nicht standardisiert wurde.Ich weiß nicht, wie lange das standardkonforme Formular in GCC war, aber ich bin mir ziemlich sicher, dass 4.2 es hatte. Wahrscheinlich viel frühere Versionen als das. – Dave

Verwandte Themen