[英]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);
這對於其他整數類型int
和long
也有重載。
如果您真的想自己編寫代碼,可以通過指定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.