2013-03-29 164 views
6

在我們代碼的各個底層部分,我們需要發送特定的字節到一個設備,以使事情發生。因此,我們有足夠的代碼看起來像:在C++中聲明char十六進制常量11

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

導致錯誤(海合會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] 

由於0xFA迴應是範圍以外-128到127

有跡象表明,我能想到的兩種解決方法:

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

或:

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

這兩者或者是難看(第一種情況),或具有其它缺點(具有投射到(常量字符*)在後者的情況下)

是否有更好的方法來聲明的這些字符串?

+4

由於您在技術上使用'unsigned char's,您爲什麼需要轉換爲'char'?沒有一個真正的整潔的解決方案,沒有用宏來隱藏轉換。 – Dave

+2

@Dave:不幸的是,C和C++中「字節數組」的通用符號是'char *',而不是'unsigned char *'。所以這就是爲什麼你通常需要演員。是的,它確實應該是'void *',但是很多API都採用'char *'s代替。 –

回答

4

C++ 11給你variadic templates(與已經存在了一段時間GCC支持)來解決這個問題。

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

或避免重複調用.data()它傳遞到C funcs中:

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?"); 

沒有開銷比較普通字符數組。

1

你可以做這樣的事情有一個單一的投:

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

既然你指定的C++ 11,我會假設你可以使用variadic macros。在這種情況下,有一種解決方案在使用時非常優雅,但在進入幕後時卻很醜陋。

所以,我會向您展示你如何使用它開始:

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

而現在,後端代碼:這可能是短,但我已經使用了標準的循環方法,所以你可以得到一些重新使用它。它可以支持1 - 24字節的列表。它可以通過重複最後一行來做得更大。歡迎來到預處理器元編程的世界。

#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

可變宏是否向後兼容C++ 03?或者,我們可以接受的是,他們在早期版本中引入了GCC擴展(比如GCC 4.2)嗎? – Damien

+1

@Damien:是的(GCC擴展),但是如果你回到足夠遠的話,語法會改變爲命名參數,並帶有'nameOfArgs ...'。在我的項目中,我有檢查交換可變宏(我使用最後幾行的註釋表單來保留常見位的所有更改),但這顯然意味着更多的代碼。問題是這個在C99和C++ 11之前是不規範的。我不知道GCC中符合標準的表單有多長時間,但我確信4.2已經存在。可能比這更早的版本。 – Dave

相關問題