簡體   English   中英

將uint16_t解釋為int16_t

[英]Interpreting a uint16_t as a int16_t

是否存在一種可移植且安全的方式將boost::uint16_t的位模式解釋為boost::int16_t 我有一個uint16_t ,我知道它表示一個編碼為little-endian的有符號16位整數。 我需要對此值執行一些帶符號的算術運算,因此是否有說服編譯器它已經是一個帶符號的值?

如果我沒記錯的話, static_cast<int16_t>會轉換該值,也許會更改其位模式。

如果要查找與boost::int16_t不同的內容,則將其內存表示形式復制到boost::int16_t內存表示形式中,因為它的表示形式始於此。

編輯:如果您必須使其在大型字節序計算機上工作,只需向后復制字節。 使用std::copystd::reverse

只需使用靜態強制轉換。 如果您碰巧在以不同方式定義它們的平台上,那么更改位模式恰好是您想要的。

redefined_cast或任何等效的指針強制轉換是未定義的(未實現定義)。 這意味着編譯器可以自由地做一些令人討厭的事情,例如將未定義的形式緩存在寄存器中而錯過更新。 此外,如果您在位模式不同的平台上,那么繞過轉換會給您留下垃圾(就像假裝float是一個int並向其加1)。

有關更多信息,請參見C中的有符號轉換為無符號轉換-始終安全嗎? 但是摘要C以一種繞行方式將靜態轉換(實際上是普通C轉換)定義為通過將x86上的位相同(使用二進制補碼)來獲得的確切結果。

不要與編譯器打交道(這始終在該編譯器上起作用,因此可以肯定的是,它們不會通過更改它來破壞每個人的代碼)。 歷史證明你錯了。

屏蔽掉除符號位以外的所有符號,將其存儲在帶符號的int中,然后使用符號位設置符號。

我猜*(boost::int16_t*)(&signedvalue)可以工作,除非默認情況下您的系統體系結構不是低位優先的。 字節序會改變行為,因為在執行完上述操作后,cpu會將帶符號的值視為特定體系結構的 boost :: int16_t值(這意味着如果您的體系結構為大字節序,則會出錯)。

編輯
為了避免對*(int16_t)(&input_value)引起爭議,我將代碼塊中的最后一條語句更改為memcpy並添加了*(int16_t)(&input_value)作為附錄。 (反之亦然)。

在大型字節序計算機上,您將需要進行字節交換,然后解釋為有符號整數:

if (big_endian()) {
  input_value = (uint16_t)((input_value & 0xff00u) >> 8) |
                (uint16_t)((input_value & 0x00ffu) << 8);
}
int16_t signed_value;
std::memcpy (&signed_value, &input_value, sizeof(int16_t));

在大多數計算機上,您可以將對memcpy的調用更改為signed_value = *(int16_t)(&input_value); 嚴格來說,這是未定義的行為。 這也是一個使用極為廣泛的習語。 幾乎所有的編譯器都使用此語句執行“正確的事情”。 但是,與語言擴展YMMV一樣,情況總是如此。

另外,最大化(但不能確保)可移植性的最佳方法是將那些帶符號的16位整數存儲為網絡順序的帶符號的16位整數,而不是以小端順序存儲為無符號的16位整數。 這給目標計算機帶來了負擔,使其能夠將那些16位網絡順序帶符號整數轉換為目標格式的16位帶符號整數。 並非每台機器都支持此功能,但是大多數可以連接到網絡的機器都支持。 畢竟,該文件必須通過某種機制到達目標計算機,因此,它很可能理解網絡順序。

另一方面,如果您通過某個專有的串行接口將該二進制文件轉換為嵌入式計算機,則可移植性問題的答案與您告訴醫生“這樣做會很痛”時得到的答案相同。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM