2017-10-07 58 views
6

給定一個包含int(小尾數)的char型緩衝區c。 如何將其讀爲int32_t?什麼是從char *緩衝區讀取int32_t的慣用cpp14方法?

我寫了這段代碼,但它不覺得習慣cpp。

int32_t v; 
char* p = (char*)&v; 
for (int i=0; i < 4; i++) { 
    *(p+i) = *(c+i); 
} 
+0

@ DavidHaim它有道理我試過這個 int32_t v = static_cast < int32_t >(* c); 但它不起作用 – Pierrot

+0

@DavidHaim例如。這個演員在大前輩身上失敗了?或者,根據使用情況,你會得到UB(嚴格別名)? – deviantfan

+4

使用位移和|有什麼錯誤運營商? –

回答

5

如果你想解決您的問題在便攜和安全的方式,使用memcpyn.m.'s answer explains。否則,這是一個更危險的技術:

請注意,這是UB。只有使用下面的技巧,如果你完全是確定緩衝區包含適量的數據,並且緩衝區和數據是正確對齊

如果您確信該系統的字節序匹配存儲在char*緩衝區中的數據的一個,你可以使用reinterpret_cast

std::int32_t v = *reinterpret_cast<std::int32_t*>(p); 

有做上述轉換的不符合標準的方式。有關更多詳細信息,請參閱this question

+7

重新解釋轉換不適用於不正確對齊的數據。行爲是未定義的。 –

+0

@ n.m。如果數據或緩衝區沒有正確對齊,它只是未定義的,對嗎?即如果OP的示例緩衝區和目標'int32'正確對齊,這將會很好。 –

+1

我的理解是,嚴格的別名不僅僅是對齊,而是關於允許處理器進行快捷方式。因此,不管是使用'char *','unsigned char *'還是(現在)'std :: byte *'以外的其他內容來別名存儲都是未定義的行爲。 https://stackoverflow.com/questions/9964418/strict-aliasing-and-alignment – Galik

6

沒有神奇的慣用方式來處理排序 - 排序是I/O問題。可以使用htonl()ntohl()函數(每系統上可用),或者只是自己解碼它們(如您所做的那樣)。我建議編寫函數來做到這一點(讓你的生活更輕鬆,更可證實)。

+1

應該注意的是,這些函數可以從* big endian *(網絡字節順序)轉換爲和* end,而問題是詢問從* little endian *轉換。 – Galik

+0

嗯,你說得對。哎呀! –

+0

謝謝@Dúthomhas你也回答了幫助 – Pierrot

3

沒有標準功能來發現您的syatem的字節順序。但是給出了這樣的功能bool is_little_endian(),只有在小端系統返回true,你可能會做這樣的事情:

std::uint32_t read_from_little_endian(char* buf) 
{ 
    std::uint32_t u; 

    if(is_little_endian()) 
     std::copy(buf, buf + sizeof(u), (char*)&u); 
    else 
     std::reverse_copy(buf, buf + sizeof(u), (char*)&u); 

    return u; 
} 

重要的一點是始終投你std::uint32_t*char*因爲只有char*可以合法別名所有其他類型。

+1

實際上,有一個相當標準的方法來_discover_ endianness - 你甚至可以讓預處理器爲你做:使用字節字符串/數組並比較一個int。 (現在,如果只有被標準化......) –

+0

@Dúthomhas不同的字符集/編碼失敗 – deviantfan

+0

@deviantfan呃,命名字符集/編碼,這是不同的代碼0和1. –

7

唯一可移植的方式從一個char*緩衝區拷貝二進制數據的任何其他數據類型與memcpy(或等效的字節拷貝merhod如std::copy或自己的一個模仿此行爲)。

memcpy(&my_number, my_buffer, sizeof(my_number)); 

當然,緩衝區應該包含給定數據類型的正確位。如果它起源於內存複製相同的數據tyoe在同一臺機器上,則endianness不起作用。否則,你必須按照需要的順序重新排列字節(就地或在一個臨時緩衝區中),或者在整數本身(也許用htonl和朋友)中以平臺相關的方式交換字節。

+0

我不會說這是唯一的方法,工會在這裏似乎也很好。 –

+0

沒有什麼能夠阻止你編寫你自己的循環或者使用像'std :: copy'這樣的標準算法。只要你使用'char *','unsigned char *','std :: byte *',這在法律上是別名的。 – Galik

+0

@Galik如果你能正確地做到這一點,你不需要問這個問題。 –