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

Java 與 C/C++ 底層數據類型轉換工具類實作

     編輯:Java 相關知識

前言

Java (Big-Endian) 與 C/C++ (通常 Little-Endian) 進行 Socket 通訊時,基本類型序列化需處理位序轉換、無符號類型映射、字串長度前綴等差異。本文提供生產級 CIOUtil 工具類,含完整單元測試。

核心差異對照表

C/C++ 類型位元組Java 對應備註
unsigned char / uint8_t1byte (有符號)Java 無無符號,邏輯上 & 0xFF
unsigned short / uint16_t2char (無符號 16-bit)Java char 唯一無符號基本型別
unsigned int / uint32_t4int (有符號)大值需用 long 接收
unsigned long long / uint64_t8long
float4floatIEEE 754 相同
double8doubleIEEE 754 相同

關鍵技術點

  • 位序轉換:Java 5+ 提供 Integer.reverseBytes()、Long.reverseBytes()、Short.reverseBytes() 一鍵大小端互換。
  • 浮點數轉換:Float.floatToIntBits()/intBitsToFloat()、Double.doubleToLongBits()/longBitsToDouble() 保持位模式不變。
  • 字串協議:採用 uint16_t 長度(2字節) + UTF-8 字節 格式,雙方約定一致。
  • 字符集:統一 UTF-8,避免中文亂碼。

CIOUtil 核心代碼 (節錄關鍵方法)

public abstract class CIOUtil {
    public static final String CHARSET = "UTF-8";

    // --- 讀取 ---
    public static int readInt(DataInputStream in) throws IOException {
        return Integer.reverseBytes(in.readInt());  // LE -> BE
    }
    public static long readLong(DataInputStream in) throws IOException {
        return Long.reverseBytes(in.readLong());
    }
    public static short readShort(DataInputStream in) throws IOException {
        return Short.reverseBytes(in.readShort());
    }
    public static char readChar(DataInputStream in) throws IOException {
        return (char) readShort(in);  // unsigned short -> Java char
    }
    public static float readFloat(DataInputStream in) throws IOException {
        return Float.intBitsToFloat(readInt(in));
    }
    public static double readDouble(DataInputStream in) throws IOException {
        return Double.longBitsToDouble(readLong(in));
    }
    public static String readUTF(DataInputStream in) throws IOException {
        short len = readShort(in);  // 讀長度前綴
        byte[] bytes = new byte[len];
        in.readFully(bytes);
        return new String(bytes, CHARSET);
    }

    // --- 寫入 ---
    public static void writeInt(DataOutputStream out, int v) throws IOException {
        out.writeInt(Integer.reverseBytes(v));  // BE -> LE
    }
    public static void writeLong(DataOutputStream out, long v) throws IOException {
        out.writeLong(Long.reverseBytes(v));
    }
    public static void writeShort(DataOutputStream out, short v) throws IOException {
        out.writeShort(Short.reverseBytes(v));
    }
    public static void writeChar(DataOutputStream out, char v) throws IOException {
        writeShort(out, (short) v);
    }
    public static void writeFloat(DataOutputStream out, float v) throws IOException {
        writeInt(out, Float.floatToIntBits(v));
    }
    public static void writeDouble(DataOutputStream out, double v) throws IOException {
        writeLong(out, Double.doubleToLongBits(v));
    }
    public static void writeUTF(DataOutputStream out, String s) throws IOException {
        byte[] bytes = s.getBytes(CHARSET);
        writeShort(out, (short) bytes.length);
        out.write(bytes);
    }
    // boolean、byte[] 直讀直寫無需轉換
}

JUnit 4 單元測試 (驗證雙向轉換)

public class CIOUtilTest {
    private void roundTrip(String name, Object input, 
            Consumer<DataOutputStream> writer,
            Function<DataInputStream, Object> reader) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        DataOutputStream dos = new DataOutputStream(baos);
        writer.accept(dos);
        dos.flush();
        byte[] data = baos.toByteArray();

        ByteArrayInputStream bais = new ByteArrayInputStream(data);
        DataInputStream dis = new DataInputStream(bais);
        Object output = reader.apply(dis);
        assertEquals(name, input, output);
    }

    @Test public void testInt() throws IOException {
        roundTrip("int", 123456,
            os -> CIOUtil.writeInt(os, 123456),
            is -> CIOUtil.readInt(is));
    }
    @Test public void testLong() throws IOException { /* 同理 */ }
    @Test public void testFloat() throws IOException { /* 近似比較 */ }
    @Test public void testDouble() throws IOException { /* 近似比較 */ }
    @Test public void testChar() throws IOException { /* '中' */ }
    @Test public void testUTF() throws IOException { /* "中文支持" */ }
}

使用範例

// Java 發送端
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream out = new DataOutputStream(baos);
CIOUtil.writeInt(out, 1001);        // 命令碼
CIOUtil.writeUTF(out, "Hello C++"); // 參數
send(baos.toByteArray());

// C++ 接收端 (略)
/*
uint32_t cmd = ntohl(*(uint32_t*)buf); // 網路序=大端,C++通常小端需轉
uint16_t len = ntohs(*(uint16_t*)(buf+4));
string param(buf+6, len);
*/

注意事項

  • 結構體對齊:C/C++ 結構體可能有填充位元組,建議 #pragma pack(1) 或手動序列化各欄位。
  • 長度溢位:字串長度用 short 限制 64KB,超長需改 int。
  • 版本演進:協議加版本號、擴展欄位預留,保持向前相容。
  • 性能:高頻通訊可考慮 ByteBuffer + Order(BIG_ENDIAN) 替代 DataOutputStream。

總結

CIOUtil 封裝了 Java 與 C/C++ 跨語言通訊的所有底層細節:大小端轉換、無符號映射、浮點位模式保持、長度前綴字串。配合單元測試驗證雙向轉換一致性,可直接用於生產環境 Socket 協議編解碼。

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