給定一個包含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);
}
給定一個包含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);
}
如果你想解決您的問題在便攜和安全的方式,使用memcpy
爲n.m.'s answer explains。否則,這是一個更危險的技術:
請注意,這是UB。只有使用下面的技巧,如果你完全是確定緩衝區包含適量的數據,並且緩衝區和數據是正確對齊。
如果您確信該系統的字節序匹配存儲在char*
緩衝區中的數據的一個,你可以使用reinterpret_cast
:
std::int32_t v = *reinterpret_cast<std::int32_t*>(p);
有做上述轉換的不符合標準的方式。有關更多詳細信息,請參閱this question。
重新解釋轉換不適用於不正確對齊的數據。行爲是未定義的。 –
@ n.m。如果數據或緩衝區沒有正確對齊,它只是未定義的,對嗎?即如果OP的示例緩衝區和目標'int32'正確對齊,這將會很好。 –
我的理解是,嚴格的別名不僅僅是對齊,而是關於允許處理器進行快捷方式。因此,不管是使用'char *','unsigned char *'還是(現在)'std :: byte *'以外的其他內容來別名存儲都是未定義的行爲。 https://stackoverflow.com/questions/9964418/strict-aliasing-and-alignment – Galik
沒有標準功能來發現您的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*
可以合法別名所有其他類型。
實際上,有一個相當標準的方法來_discover_ endianness - 你甚至可以讓預處理器爲你做:使用字節字符串/數組並比較一個int。 (現在,如果只有
@Dúthomhas不同的字符集/編碼失敗 – deviantfan
@deviantfan呃,命名字符集/編碼,這是不同的代碼0和1. –
唯一可移植的方式從一個char*
緩衝區拷貝二進制數據的任何其他數據類型與memcpy
(或等效的字節拷貝merhod如std::copy
或自己的一個模仿此行爲)。
memcpy(&my_number, my_buffer, sizeof(my_number));
當然,緩衝區應該包含給定數據類型的正確位。如果它起源於內存複製從相同的數據tyoe在同一臺機器上,則endianness不起作用。否則,你必須按照需要的順序重新排列字節(就地或在一個臨時緩衝區中),或者在整數本身(也許用htonl和朋友)中以平臺相關的方式交換字節。
我不會說這是唯一的方法,工會在這裏似乎也很好。 –
沒有什麼能夠阻止你編寫你自己的循環或者使用像'std :: copy'這樣的標準算法。只要你使用'char *','unsigned char *','std :: byte *',這在法律上是別名的。 – Galik
@Galik如果你能正確地做到這一點,你不需要問這個問題。 –
@ DavidHaim它有道理我試過這個 int32_t v = static_cast < int32_t >(* c); 但它不起作用 – Pierrot
@DavidHaim例如。這個演員在大前輩身上失敗了?或者,根據使用情況,你會得到UB(嚴格別名)? – deviantfan
使用位移和|有什麼錯誤運營商? –