首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

網路位元組序轉換:C 無符號類型到 Java 長整型/字元/短整型的完整實作

     編輯:關於C語言

背景與挑戰

Java 無無符號基本類型,所有整數均為帶號。當從網路(大端序)讀取 C/C++ 發送的無符號 byte、short、int 時,必須在 Java 端以更寬的帶號類型(short、int、long)接收,並透過位元運算還原無符號數值。

核心原理:位元遮罩與移位組合

  • 單位元組:0xFF & b 取低 8 位,轉為 short 即得 0~255。
  • 雙位元組:高位左移 8 位 | 低位,得 0~65535,存入 int(Java char 亦為 16 位無符號)。
  • 四位元組:依序左移 24、16、8、0 位並 | 合成,最後 & 0xFFFFFFFFL 強制視為 32 位無符號,存入 long。

原始碼逐段解析

byte[] buf = getNetData();   // 假設已讀取網路資料
int index = 0;

// 1 byte → unsigned byte (0~255) → Java short
int firstByte = 0xFF & buf[index++];
short anUnsignedByte = (short) firstByte;

// 2 bytes → unsigned short (0~65535) → Java char
firstByte = 0xFF & buf[index];
int secondByte = 0xFF & buf[index + 1];
index += 2;
char anUnsignedShort = (char) (firstByte << 8 | secondByte);

// 4 bytes → unsigned int (0~4294967295) → Java long
firstByte = 0xFF & buf[index];
secondByte = 0xFF & buf[index + 1];
int thirdByte = 0xFF & buf[index + 2];
int fourthByte = 0xFF & buf[index + 3];
index += 4;
long anUnsignedInt = ((long) (firstByte << 24
                    | secondByte << 16
                    | thirdByte << 8
                    | fourthByte)) & 0xFFFFFFFFL;

關鍵細節深度剖析

1. 0xFF & buf[i] 的必要性

Java byte 為帶號,負值擴展為 int 時會符號擴展(高 24 位變 1)。& 0xFF 強制清零高位,只保留原始 8 位元模式,得到 0~255 的 int 值。

2. 移位運算優先級與型別提升

firstByte << 8 會先將 firstByte 提升為 int 再移位,結果仍為 int。四位元組合成時,最外層轉 (long) 確保 32 位不溢位,最終 & 0xFFFFFFFFL 消除符號位影響。

3. 大端序假設

程式碼假設網路資料為 Big-Endian(高位在前),符合 RFC 1700 網路位元組序標準。若傳送端為小端序,需反轉索引順序。

通用工具類封裝

public final class UnsignedBytes {
    private UnsignedBytes() {}

    public static int toUnsignedByte(byte b) {
        return b & 0xFF;
    }

    public static int toUnsignedShort(byte[] buf, int offset) {
        return ((buf[offset] & 0xFF) << 8) | (buf[offset + 1] & 0xFF);
    }

    public static long toUnsignedInt(byte[] buf, int offset) {
        return (((long) buf[offset] & 0xFF) << 24)
             | (((long) buf[offset + 1] & 0xFF) << 16)
             | (((long) buf[offset + 2] & 0xFF) << 8)
             | ((long) buf[offset + 3] & 0xFF);
    }

    // 便利方法:直接回傳 Java 對應寬類型
    public static short asShort(byte b) { return (short) toUnsignedByte(b); }
    public static char asChar(byte[] buf, int offset) { return (char) toUnsignedShort(buf, offset); }
    public static long asLong(byte[] buf, int offset) { return toUnsignedInt(buf, offset); }
}

效能優化建議

  • 使用 ByteBuffer:ByteBuffer.wrap(buf).order(ByteOrder.BIG_ENDIAN).getShort() 等原生方法,JIT 會優化為內部指令。
  • 避免重複建立陣列切片,傳遞 offset 索引。
  • 熱點路徑可考慮 Unsafe 或 VarHandle (Java 9+) 直接存取記憶體。

測試驗證

C 傳送值位元組序列Java 解析結果
uint8_t 200C8short 200
uint16_t 50000C3 50char 50000
uint32_t 3000000000B2 D0 5E 00long 3000000000

延伸:浮點數與自定義結構體

IEEE 754 浮點數位元模式可直接用 Float.intBitsToFloat/Double.longBitsToDouble 轉換。結構體序列化建議採用 Protocol Buffers、FlatBuffers 或自訂 TLV 協議,避免手工位元操作維護成本過高。

總結

跨語言無符號整數傳輸的核心在於:位元遮罩消除符號擴展 + 移位組合還原數值 + 寬類型承載結果。掌握此模式,即可在 Java、C#、Go、Python 等無/有無符號類型語言間安全互通。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved