为什么要进行位移操作?

12

我最近查看了一个配置文件,里面保存了一些晦涩的值。我碰巧有源代码可用,所以就看了看它在做什么,结果是将许多不同的值和位移操作融合到了一起。这让我感到困惑为什么有人会这样做。我的问题是:采用这种方式存储数字数据是否有明显的优势?我可以看出来,这可能使得存储的值在字节方面稍微更小,但似乎要花费大量工作才能节省几个字节的存储空间。而且,它似乎会显著地变慢。

另一个可能性是它被用于混淆目的。位移操作常用于混淆吗?


2
通过位移混淆可能是最不有效的手段之一。 - KevinDTimm
@KevinDTimm 我曾经看到过一个配置文件,它是通过将每个字符放入单独的缓冲区中,然后将两个缓冲区合并而生成的。因此,文件 configParam = true 变成了 cnfgaa reofiPrm=tr。现在对于单个参数来说,它可能看起来足够混淆,以至于不能立即找出正确的值。但是对于整个文件来说,这种模式就非常明显了。唯一的问题是,它不仅仅是一个配置文件,还是一个许可证文件... 嗯哼... 我想他们认为只使用纯文本并强制执行哈希签名太复杂了... - corsiKa
是的,我也看到了一段代码。func SizeVarint(x uint64) int { switch { case x < 1<<7: return 1 case x < 1<<14: return 2 case x < 1<<21: return 3 case x < 1<<28: return 4 case x < 1<<35: return 5 case x < 1<<42: return 6 case x < 1<<49: return 7 case x < 1<<56: return 8 case x < 1<<63: return 9 } return 10 } - lokanadham100
4个回答

11

这是位移的常见用法之一。具有以下几个优点:

1)位移操作速度快。

2)您可以在单个值中存储多个标志。

如果您有一个应用程序具有多个功能,但您只想启用某些(可配置的)功能,则可以执行以下操作:

[Flags]
public enum Features
{
    Profile = 1,
    Messaging = 1 << 1,
    Signing = 1 << 2,
    Advanced = 1 << 3
}

启用消息和高级功能的单个值为:

(1 << 1) + (1 << 3) = 2 + 16 = 18

<add name="EnabledFeatures" value="18" />

然后,要确定给定的功能是否启用,只需执行一些简单的位运算:

var AdvancedEnabled = 
    EnabledFeatures & Features.Advanced == Features.Advanced;

1
我无法想象在从文件中收集一些值时,它会明显地更快...而且在这种应用程序中的空间节省似乎微不足道。也许开发人员只是选择了他/她熟悉的东西。 - Jeremy Holovacs
你也可以对值(通常是状态变量)进行奇怪的And/Or/Xor逻辑运算,以确定“合并”状态。非常奇怪,但我在3D应用程序中看到过,在渲染内核中,这实际上是保持逻辑复杂性而不会影响性能的唯一解决方案。 - Tigran
1
这与拥有一个枚举,其值为1、2、4、8、16等有明显的不同之处在哪里?这会带来什么好处? - Jeremy Holovacs
1
@Jeremy - 这是一样的。使用枚举值可以允许您使用按位运算。 - Justin Niessner
1
离题了,但要注意[Flags]枚举中的0值,因为你无法判断它是否存在。 - DK.

5
位移操作在像C、C++和汇编语言这样的系统级别语言中似乎更为常见,但我也在C#中偶尔见到它的应用。使用位移操作并不是为了节省空间,而是有以下两个典型原因之一(或者两个都有):
  • 你正在与现有系统通信(或使用已建立的协议、生成已知格式的文件),这些需要非常精确地排列;和/或
  • 位组合成的值本身对于测试很有用。
那些只出于节省空间或混淆代码的目的在高级语言中使用它的人几乎总是过早优化(或者是白痴)。空间节省很少能够证明增加的复杂性是值得的,而且位移操作并不足够复杂,无法阻止一个决心理解你的代码的人。

在我看来,这就是答案:配置文件中似乎没有为增加的复杂性提供正当理由。不过听到位移操作的实际用途还是很好的。 - Jeremy Holovacs
你可能需要将两个“short”类型的变量存储在ASP.net会话状态的一个“int”整数字段中,以避免读取和锁定会话来读取两个单独值的开销。此外,还可以节省将两个值存储在会话中的开销。 - David d C e Freitas
2
@David:那是一个典型的例子,不应该使用它,除非你进行了分析并发现你的应用程序之所以太慢完全是因为你读取了两个会话参数而不是一个。(专业提示:除非你是微软,否则很可能***不是这种情况。更有可能的是你的算法有问题。) - cHao

4
我有一个项目需要存储一周内每天/小时的可用时间矩阵。因此,需要以某种方式存储24x7个值。
我选择将其存储为7个整数,因此每天用一个整数表示,其中每小时用一个位表示。这只是一个可以使用的示例。 enter image description here

附加好处:if (available_hours[0] != 0) 可以判断你在周日(或周一,如果你喜欢的话)是否有空。 - cHao
没错,确实如此... 只需使用简单的AND或OR操作,就可以立即计算出各种重叠。 - Daniel Mošmondor
有用且信息量大。我可以看到很多地方可以使用它。然而,它被用在配置文件中的方式似乎并不合理。 - Jeremy Holovacs

1
有时候(尤其是在旧版的Windows编程中),一个值的“高位”和“低位”会被编码成信息...有时需要进行移位才能获取信息。我不确定背后的原因,除了可能使返回两个32位值编码在其中的64位值变得方便(这样你可以通过单个方法调用的返回值来处理它)。
我同意你对于不必要复杂性的主张,除了真正重型数学计算/密码学之外,我不认为有很多应用场景需要这种技术。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接