簡體   English   中英

通過套接字發送 int:有符號 vs 無符號

[英]send int over socket: signed vs unsigned

假設我想通過網絡發送 4 字節整數。 由於使用來自stdint類型,整數具有固定大小。 我的問題是:如果我嘗試使用這 4 個字節發送有符號或無符號整數,這有關系嗎? (假設我使用相同的方法在客戶端和服務器端將整數序列化/反序列化為字節/從字節序列化)。 會不會有其他問題? (我也沒有提到字節序問題)

這個問題很少得到應有的關注。

正如 Floris 所觀察到的,只有表示的字節被發送。 C 和 C++ 定義了無符號數的按位表示*,而不是有符號數,因此將有符號數作為字節發送會造成兼容性差距。

很容易“修復”傳輸格式。 將有符號 int 轉換為其相應的無符號類型可以保證生成二進制補碼表示。 但是如何轉換回來呢? 當你想要一個負數時,將一個無符號整數轉換為它的有符號整數會產生有符號整數溢出,這會產生一個未指定的結果——你可以得到任何東西。

為了真正安全,請使用分支:

signed int deserialize_sint( unsigned int nonnegative ) {
    if ( nonnegative < INT_MAX ) return nonnegative;
    else return - (int) ( - nonnegative ); // Only cast an unsigned number < INT_MAX
}

幸運的是,編譯器會發現兩種情況相同並消除分支。

上面的函數是用C寫的; 向 C++ 人群道歉。

如果你想變得更加偏執,你可以在執行- nonnegative < INT_MAX之前檢查- nonnegative < INT_MAX ,因為二進制補碼中最負的數仍然會溢出一個補碼機器。 對於nonnegative == - nonnegative的情況,您可以做的最好的事情是返回更寬的類型,或者如果不可能,則標記運行時錯誤。

* 不過,當位被分成一個字節序列時,字節序變得不明確。

當您通過套接字發送一個數字時,它只是字節。

現在如果你想發送一個負數,而在接收端負數的表示是不同的,那么你可能會遇到問題。 否則,它只是字節。

因此,如果負數的二進制表示有可能在接收端被誤解,那么您需要進行一些轉換(可能發送一個符號字節后跟四個大小字節,並在另一端將它們放在一起)。

不過這不太可能。

因為該標准沒有強制要求對簽名類型進行特定表示:

3.9.1 基本類型 [basic.fundamental] n3936 第 7 段

類型 bool、char、char16_t、char32_t、wchar_t 以及有符號和無符號整數類型統稱為整數類型。 整數類型的同義詞是整數類型。 整數類型的表示應使用純二進制計數系統定義值。 [示例:本國際標准允許整數類型使用 2 的補碼、1 的補碼和帶符號的幅度表示 —結束示例]

以二進制表示形式發送有符號整數值並沒有明確定義(除非您明確將此作為協議的一部分並進行一些手動工作以確保您知道如何讀/寫該二進制表示)。

根據具體要求,有幾種解決方案。

  • 如果速度不是主要問題,那么您可以使用英語(您選擇的替代語言)表示並將整數序列化為文本。 對於很多問題,這不是一個糟糕的解決方案,因為主要的速度障礙不是序列化成本,而是網絡延遲。 在大多數情況下(但並非總是如此),網絡延遲是主要問題。
  • 因此,或者,如果您需要二進制表示(因為您對其進行了計時並且數字的體積/密度需要它)。 那么由於htonl()和family,字節序問題不難解決。 它涵蓋了所有無符號整數類型(至少 16/32 位值)。
    • 所以你真正需要解決的就是有符號值的表示。 所以選擇一個(使用最常見的表示你使用的機器,然后翻譯通常是空操作)。 但是,如果您知道在線表示(因為它在您的協議中指定),那么您可以在本機不支持此表示的機器上轉換為/從該表示(通常此成本很小(有條件的添加))。

暫無
暫無

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

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