簡體   English   中英

C#簽名/未簽名的演員問題

[英]C# signed/unsigned cast issues

我需要在有符號整數和它們的內部表示之間轉換為一系列字節。 在CI中使用的功能如下:

unsigned char hibyte(unsigned short i)
{return i>>8;}

unsigned char lobyte(unsigned short i)
{return i & 0xFF;}

unsigned short makeshort(unsigned char hb, unsigned char lb)
{return ((short)hb << 8) | (short)lb;}

問題是這個代碼在C#下不起作用,因為簽名/無符號強制轉換的規則是不一樣的:因為我理解C#轉換意味着值的轉換,而在有符號/無符號類型之間的C轉換中不修改基礎數據。 此外,在C#中,對於帶符號的數字,>>運算符在符號位中移位。 所有這些使我很難將我的代碼轉換為C#,例如

1)C#功能

public static byte hibyte(short i)
{return (byte) (i>>8);}

如果我是否定的,則拋出溢出異常

2)C#功能

public static ushort makeshort(byte hb, byte lb)
{return (short) (((ushort)hb << 8) | (ushort)lb); }

如果結果為short,則拋出溢出異常。 這里的表達式“(ushort)hb << 8”起作用,因為移位是在無符號數上完成的。 但后來我需要將相同的數據解釋為有符號整數,我不知道該怎么做。 我理解C#這樣的類C演員是作弊的,因為正值可能會變成負值,但這是我實際需要的(例如,處理從設備讀取的字節流等)。目前我正在使用對於像這樣的所有二進制操作編譯為非托管dll的C代碼,但這不是很優雅,我確信這可以在C#中以某種方式(可能簡單地)完成。 歡迎任何建議!

您可以使用BitConverter類來執行此操作:

short x = 1;
byte[] bytes = BitConverter.GetBytes(x);
short y = BitConverter.ToInt32(bytes, 0);

這對於其他整數類型intlong也有重載。

如果您真的想自己編寫代碼,可以通過指定unchecked來避免溢出異常,如下所示:

public static byte hibyte(short i)
{
    unchecked
    {
        return (byte)(i >> 8);
    }
}

public static ushort makeushort(byte hb, byte lb)
{
    unchecked
    {
        return (ushort)((hb << 8) | lb);
    }
}

public static short makeshort(byte hb, byte lb)
{
    unchecked
    {
        return (short)((hb << 8) | lb);
    }
}

我只是使用BitConverter ; 它很快。 但請注意,它始終使用運行代碼的計算機的字節順序。

這是通過BitConverter.IsLittleEndian報告的。

如果您要轉換的數據具有不同的字節順序,則必須自己完成。

幾個答案已經注意到BitConverter類,以及使用unchecked位移和強制轉換。 我將快速演示第三種選擇:“C風格的聯合結構”。

[StructLayout(LayoutKind.Explicit)]
struct Converter
{
   [FieldOffset(0)]
   public ushort UshortValue;
   [FieldOffset(0)]
   public short ShortValue;
   [FieldOffset(0)]
   public byte LoByte;    
   [FieldOffset(1)]
   public byte HiByte;
}

然后像這樣使用。

ushort test1 = new Converter { ShortValue = -123 }.UshortValue; // 65413
ushort test2 = new Converter { HiByte = 1, LoByte = 100 }.UshortValue; // 356
byte test3 = new Converter { UshortValue = 356 }.LoByte;  // 100

它比BitConverter更有優勢,您不需要分配臨時字節數組。

正如其他人所提到的,你可以使用BitConverter類,雖然他們沒有考慮到實際代碼中的字節序(最后只是簡單提到):

public static (byte Hibyte, byte Lobyte) GetBytes(short i)
{   // This is my recommendation; it gets both bytes in one call, so it
    // may be more efficient.
    var bytes = BitConverter.GetBytes(i);
    if (BitConverter.IsLittleEndian)
        Array.Reverse(bytes)
    return (bytes[0], bytes[1]);
}

public static (byte Hibyte, byte Lobyte) GetBytes(ushort i)
{   // BitConverter works equally well with unsigned types.
    var bytes = BitConverter.GetBytes(i);
    if (BitConverter.IsLittleEndian)
        Array.Reverse(bytes)
    return (bytes[0], bytes[1]);
}

public static byte Hibyte(short i)
{   // If you want to use your original schema, here's the hi byte:
    if (BitConverter.IsLittleEndian)
        return BitConverter.GetBytes()[1];
    return BitConverter.GetBytes()[0];
}

public static byte Hibyte(ushort i)
{   // Again, same thing works for ushort
    if (BitConverter.IsLittleEndian)
        return BitConverter.GetBytes()[1];
    return BitConverter.GetBytes()[0];
}

public static short MakeShort(byte hb, byte lb)
{
    byte[] bytes = new byte[] { hb, lb };
    if (BitConverter.IsLittleEndian)
        Array.Reverse(bytes);
    return BitConverter.ToInt16(bytes);
}

public static ushort MakeUShort(byte hb, byte lb)
{
    byte[] bytes = new byte[] { hb, lb };
    if (BitConverter.IsLittleEndian)
        Array.Reverse(bytes);
    return BitConverter.ToUInt16(bytes);
}

並且,雖然其他人提到使用unchecked ,但他們忽略了一個問題:正如您在原始問題中所指出的那樣,當對有符號整數類型進行右移時,符號位會重復,因此這有效:

public static byte Hibyte(ushort i)
{ return (byte)(i >> 8); }
// No need for unchecked, because result will always fit in one byte and is never < 0.

public static byte Lobyte(ushort i)
{ return (byte)(i & 0xFF); } // No need for unchecked for the same reason.

public static byte LoByte(short i)
{ return (byte)(i & 0xFF); } 
// Like above, no need for unchecked for the same reasons; also, bitwise & works the same 
// for both signed and unsigned types.

public static ushort MakeUShort(byte hb, byte lb)
{ return (ushort)((hb << 8) | lb); } 
// Again, no need for unchecked; result is always 16 bits and never negative.

public static short MakeShort(byte hb, byte lb)
{ unchecked { return (short)((hb << 8) | lb); } }
// This time, we may need unchecked because result may overflow short.

...為簽名 short的高字節提供的代碼需要額外的演員:

public static byte Hibyte(short i)
{ unchecked { return (byte)((ushort)i >> 8); } }
// Again, the unchecked is needed, this time because i may be negative, 
// which may need to be accounted for when casting to a ushort.

通過在移位之前將帶符號的short ushort轉換為無符號的short ,我們將符號位保持在前面8次。 或者,我們可以使用按位&忽略傳播的符號位:

public static byte HiByte (short i)
{ return (byte)((i >> 8) & 0xFF); }
// Since bitwise operations never result in overflow, and by the time we cast at the end, 
// the number is guaranteed to fit in a byte and be >= 0, we no longer need any unchecked blocks.

任何這些都會產生相同的結果。

暫無
暫無

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

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