我有一个长度为 5 位的值。 4 位确定数字,第 5 位确定符号,从而保存 -16 和 +15 之间的任何值。如何在 C# 中实现从恒定位宽度扩展符号?我知道在 C 中,我可以使用类似下面的东西来完成这个:
int x; // convert this from using 5 bits to a full int
int r; // resulting sign extended number goes here
struct {signed int x:5;} s;
r = s.x = x;
如何在 C# 中做类似的事情?
我只是编写一个 C 函数(因为我不太了解 C#),它将使用我知道 C# 中可用的操作来完成此操作。
int five_bit_to_signed(int five_bit) {
int sh = (sizeof(int)*8)-5;
int x = five_bit << sh; // puts your sign bit in the highest bit.
return x >> sh; // since x is signed this is an arithmatic signed shift
}
不太清楚你的意思,但它可能很简单:
int fiveBits = normal & 0x1f;
反之亦然:
int normal = fiveBits < 16 ? fiveBits : fiveBits | -32;
如果您可以建议一些原始输入和所需的输出,那将会有所帮助。
先执行左移,然后执行算术右移,将符号位移至高位,然后再移回。算术右移将为您执行符号扩展。
当然,这取决于有效的算术移位运算。抽象 C 语言不这样做(无论是否有效,它都是实现定义的),但大多数实现都这样做。我不确定 C#,但我猜它有一个。
我知道这是一个老问题,但对于未来的搜索者,我有更多信息。
C# 不支持自定义位宽,但它支持二进制运算和 getter/setter,这使得添加兼容层相对容易。例如,如果您想将原始数据存储在 byte _num 中,但希望能够使用标准 C# sbyte 与其进行交互,您可以使用以下命令:
byte _num;
sbyte num {
get
{
return (sbyte)(((_num & 0x10) << 3) | (_num & 0x0F));
}
set
{
_num = (byte)((value & 0x0F) | ((value & 0x80) >> 3));
}
}
这种 shell 在与低级固件或嵌入式项目交互时特别有用。
从你的问题来看,你似乎希望有一个可以轻松地与
int
类型相互转换的结构:
struct FiveBit
{
public int bits;
public static implicit operator int(FiveBit f)
{
return (f.bits & 0x10) == 0 ? f.bits : f.bits | -32;
}
public static implicit operator FiveBit(int r)
{
return new FiveBit() { bits = r & 0x1f };
}
}
这是一个用法示例:
class FiveBitTest
{
static void Main(string[] args)
{
FiveBit f = new FiveBit();
int r; // resulting sign extended number goes here
f.bits = 0;
r = f;
Console.WriteLine("r = {0}, f.bits = 0x{1:X}", r, f.bits);
f.bits = 0x1f;
r = f;
Console.WriteLine("r = {0}, f.bits = 0x{1:X}", r, f.bits);
r = -2;
f = r;
Console.WriteLine("r = {0}, f.bits = 0x{1:X}", r, f.bits);
}
上面的输出是:
r = 0, f.bits = 0x0
r = -1, f.bits = 0x1F
r = -2, f.bits = 0x1E
这是任何位宽的通用解决方案:
/// <summary>
/// Reinterprets a raw unsigned 32 bit integer as a signed value of a given width.
/// If the signed value is negative, the sign bits are extended to create the equivalent 32 bit signed integer.
/// </summary>
/// <param name="rawValue">The raw unsigned 32 bit integer</param>
/// <param name="width">The width of the signed integer, in bits</param>
/// <returns></returns>
int ExtendSign(uint rawValue, int width)
{
// Generate a mask that extends from the most significant bit, down to and covering the sign bit of the value
uint mask = (uint)(int.MinValue >> ((sizeof(int) * 8) - width));
// Check if the value is negative
if ((rawValue & mask) != 0)
{
// If so, extend the sign bit all the way to the MSB
rawValue |= mask;
}
return (long)rawValue;
}
对于 5 位值的情况,您可以这样称呼它:
int r = ExtendSign(x, 5);
你可以