【问题标题】:How to do -1 on a specific byte of an integer in C#?如何在 C# 中对整数的特定字节执行-1?
【发布时间】:2018-06-16 09:16:00
【问题描述】:

我有一个整数 u=101057541。

二进制,这等于:00000110 00000110 00000100 00000101

现在,我将每个字节视为一个单独的小数(在本例中为 6、6、4、5)。 我想从第一个字节中减去 -1,得到 6-1=5。 我尝试这样做:

int West = u | (((u>>24) - 1) << 24);

但是,结果与我 ADD 1 到该字节时的结果相同。有人可以解释为什么并告诉我如何从这个字节中减去 -1 吗?

更新: 因此,我想要的结果是以下二进制数:

00000101 00000110 00000100 00000101

【问题讨论】:

  • 你减去了-1,好吧。
  • 如果你有 u = 1;它将是00000000 00000000 00000000 00000001 => 0 0 0 1,你想在这里做什么 0-1 或 1-1 ?
  • 我想知道谁在 SO 上为这样的问题投票。
  • 感谢大家的快速回复。我现在明白我做错了什么并使用遮罩来获得正确的结果。

标签: c# byte bit-shift


【解决方案1】:

因为你正在“或”-ing 那个字节:

 u | (((u>>24) - 1) << 24);

应该是

 (u & mask) | (((u>>24) - 1) << 24);

其中mask 是除了您正在使用的字节之外的所有内容。

您可能会更容易发现不安全的代码:

int i = 101057541;
byte* b = (byte*)&i;
b[3]--; // note CPU endianness is important here
Console.WriteLine(i);

如果您使用所有最新位,您可以在不使用 unsafe 的情况下使用“spans”执行相同的操作;

int i = 101057541;
var bytes = MemoryMarshal.Cast<int, byte>(MemoryMarshal.CreateSpan(ref i, 1));
bytes[3]--; // note CPU endianness is important here
Console.WriteLine(i);

或者您可以通过具有显式布局的struct 使用“联合” - 所以 4 个字节与 1 个 int 重叠:

var x = new Int32Bytes();
x.Value = 101057541;
x.Byte3--; // note CPU endianness is important here
Console.WriteLine(x.Value);

与:

[StructLayout(LayoutKind.Explicit)]
struct Int32Bytes
{
    [FieldOffset(0)]
    public int Value;
    [FieldOffset(0)]
    public byte Byte0;
    [FieldOffset(1)]
    public byte Byte1;
    [FieldOffset(2)]
    public byte Byte2;
    [FieldOffset(3)]
    public byte Byte3;
}

【讨论】:

  • 感谢您的广泛回复。我按照你的建议做了掩蔽。像这样的东西:(u&16777215)| (((u >> 24) - 1)
  • @RutgerMauritz 如果 16777215 是 0x00FFFFFF,那么确定
  • 我确实把它改成了 0x00FFFFFF 是的。但是,我现在想对整数的第二个字节做同样的事情,在这种情况下,我尝试使用 0xFF00FFFF。但是,在这种情况下,我收到错误“无法实现。将类型 'long' 转换为 'int'”。你知道为什么会这样吗? (我对 C# 很陌生)
  • @RutgerMauritz 编译器对到达最后一位的常量感到不安——使用~0xFF0000~(0xFF &lt;&lt; 16) 可能更容易,但它说明了为什么其他方法可以更简单...
  • @RutgerMauritz 不一定,不;您会惊讶于 netcoreapp2.1 中 span 代码的效率 - huge JIT 工作让这一点变得如此出色;而unsafe 一直都很快——只是更丑。请记住,尽管unsafeSpan* 代码可能看起来很粗糙,但在 JIT 期间,大部分代码实际上都会蒸发殆尽 - 所以基本上它变成的只是一个就地 ref decr - 这是 less 工作而不是移动和掩蔽。对于性能的真正答案,建议使用像 benchmarkdotnet 这样的工具(免费等)
【解决方案2】:

当您从 00000110 中减去 1 时,结果为 00000101。您将其与原始值进行或运算,您将得到 0000111,这就像您加 1 一样。

作为解决问题的一条线,您应该屏蔽掉您正在操作的位区域。:

int West = (u & 0x00FFFFFF) | ((((u & 0xFF000000)>>24) - 1)

【讨论】:

  • 这里右边的掩码是多余的——你会在移位期间丢弃其他位;这对于内部细分市场更为重要
  • @Marc:你说得对,我想到了,我知道在当前情况下它是多余的。一般来说,最好有(防御性编码)。 u 和 West 也是有符号整数。
猜你喜欢
  • 2016-01-20
  • 2019-09-15
  • 2012-04-21
  • 2012-04-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-03
  • 2010-09-09
相关资源
最近更新 更多