位运算符,而不是在分支中使用异或

2024-04-29

问完后这个问题 https://stackoverflow.com/questions/22336015/why-use-xor-with-a-literal-instead-of-inversion-bitwise-not,我收到了 @AndonM.Coleman 的一条非常有趣的评论,我必须验证它。

由于反汇编代码是为 x86 编写的,因此值得指出的是,XOR 将设置/清除零标志,而 NOT 不会(如果您想执行按位操作而不影响依赖于先前操作标志的跳转条件,有时很有用) 。现在,考虑到您不是直接编写程序集,您确实无法以有意义的方式访问此标志,因此我怀疑这就是偏爱其中一个的原因。

他的评论让我很好奇以下代码是否会产生相同的汇编指令

#include <iostream>

int main()
{
    unsigned int val = 0;

    std::cout << "Enter a numeric value: ";
    std::cin >> val;

    if ( (val ^ ~0U) == 0)
    {
        std::cout << "Value inverted is zero" << std::endl;
    } else
    {
        std::cout << "Value inverted is not zero" << std::endl;
    }

    if ( (~val) == 0)
    {
        std::cout << "Value inverted is zero" << std::endl;
    } else
    {
        std::cout << "Value inverted is not zero" << std::endl;
    }

    return 0;
}

对于以下两个操作

if ( (val ^ ~0U) == 0 )

and

if ( (~val) == 0 )

The 未优化Visual Studio 2010 中的 build 给出以下反汇编:

    if ( (val ^ ~0U) == 0)
00AD1501  mov         eax,dword ptr [val]  
00AD1504  xor         eax,0FFFFFFFFh  
00AD1507  jne         main+86h (0AD1536h)  


    if ( (~val) == 0)
00AD1561  mov         eax,dword ptr [val]  
00AD1564  not         eax  
00AD1566  test        eax,eax  
00AD1568  jne         main+0E7h (0AD1597h)  

我的问题是关于优化的。是不是写得比较好

if ( (val ^ ~0U) == 0)

or

if ( (~val) == 0)

这取决于很多因素,但主要取决于您告诉编译器要优化的内容(如果有的话)。

如果编译器设置为优化大小(最小字节码),那么有时它会使用XOR在看似奇怪的地方。例如,X86使用的可变长度编码方案可以设置一个寄存器来0 by XOR'ing 本身的代码字节数比使用所需的代码少MOV操作说明。

考虑使用的代码XOR:

if ( (val ^ ~0U) == 0 )  /* 3-bytes to negate and test (x86) */

    XOR eax,0FFFFFFFFh需要 3 个字节AND设置/清除零标志 (ZF)

现在,考虑使用的代码NOT:

if ( (~val) == 0)        /* 4-bytes to negate and test (x86) */

    NOT eax被编码成2字节指令,但不影响CPU标志。

    TEST eax,eax添加额外的 2 个字节,并且需要设置/清除零标志 (ZF)

NOT也是一个简单的指令,但由于它不影响任何CPU标志,因此您必须发出TEST之后指示使用它进行分支,如代码中所示。这实际上会产生更大的字节码,因此设置为优化大小的智能编译器将probably尽量避免使用NOT。这两条指令一起完成所需的周期数因 CPU 代的不同而异,并且当智能编译器被告知优化速度时,也会将其纳入其决策中。


If you are not writing hand-tuned assembly, it is best to use whatever is clearest to a human and hope that the compiler is smart enough to choose different instructions/scheduling/etc. to optimize for size/speed as requested at compile-time. Compilers have a smart set of heuristics they use to choose and schedule instructions, they know more about the target CPU architecture than the average coder.

如果您后来发现这个分支确实是一个瓶颈,并且没有更高级别的方法来解决该问题,那么您可以进行一些低级别的调整。然而,如今,除非您的目标是低功耗嵌入式 CPU 或内存有限的设备,否则这是一件微不足道的事情。我通过手动调整来挤出足够的性能以使其值得的唯一地方是受益于数据并行性的算法,并且编译器不够智能,无法有效地利用 MMX/SSE 等专用指令集。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

位运算符,而不是在分支中使用异或 的相关文章

  • 通过增加索引之和来生成排序组合的有效方法

    对于启发式算法 我需要一个接一个地评估特定集合的组合 直到达到停止标准 由于它们很多 目前我正在使用以下内存高效迭代器块生成它们 受到 python 的启发 itertools combinations http docs python o
  • clang 格式换行符在错误的位置

    给出以下代码行 get abc manager get platform status abc platform status sw update status fill update status actions allowed stat
  • 在 VS2017 下使用 Conan 和 CMake 项目进行依赖管理

    我正在尝试使用 CMake 与 VS2017 集成为 C 设置一个开发环境 以便在 Linux x64 下进行编译 为了更好地管理依赖关系 我选择使用 Conan 但我对这个软件还很陌生 我想知道让 VS2017 识别项目依赖关系的最佳方法
  • 从 C 结构生成 C# 结构

    我有几十个 C 结构 我需要在 C 中使用它们 典型的 C 结构如下所示 typedef struct UM EVENT ULONG32 Id ULONG32 Orgin ULONG32 OperationType ULONG32 Size
  • 无法解析远程名称 - webclient

    我面临这个错误 The remote name could not be resolved russgates85 001 site1 smarterasp net 当我请求使用 Web 客户端读取 html 内容时 出现错误 下面是我的代
  • TcpClient 在异步读取期间断开连接

    我有几个关于完成 tcp 连接的问题 客户端使用 Tcp 连接到我的服务器 在接受客户端后listener BeginAcceptTcpClient ConnectionEstabilishedCallback null 我开始阅读netw
  • libxml2 xmlChar * 到 std::wstring

    libxml2似乎将所有字符串存储在 UTF 8 中 如xmlChar xmlChar This is a basic byte in an UTF 8 encoded string It s unsigned allowing to pi
  • 使用 WF 的多线程应用程序的错误处理模式?

    我正在写一个又长又详细的问题 但只是放弃了它 转而选择一个更简单的问题 但我在这里找不到答案 应用程序简要说明 我有一个 WPF 应用程序 它生成多个线程 每个线程执行自己的 WF 处理线程和 WF 中的错误 允许用户从 GUI 端进行交互
  • C++ 错误 - “成员初始值设定项表达式列表被视为复合表达式”

    我收到一个我不熟悉的 C 编译器错误 可能是一个非常愚蠢的错误 但我不能完全指出它 Error test cpp 27 error member initializer expression list treated as compound
  • 分配器感知容器和propagate_on_container_swap

    The std allocator traits模板定义了一些常量 例如propagate on container copy move assign让其他容器知道它们是否应该在复制或移动操作期间复制第二个容器的分配器 我们还有propag
  • 二叉树中的 BFS

    我正在尝试编写二叉树中广度优先搜索的代码 我已将所有数据存储在队列中 但我不知道如何访问所有节点并消耗它们的所有子节点 这是我的 C 代码 void breadthFirstSearch btree bt queue q if bt NUL
  • 从 R 到 C 处理列表并访问它

    我想使用从 R 获得的 C 列表 我意识到这个问题与此非常相似 使用 call 在 R 和 C 之间传递数据帧 https stackoverflow com questions 6658168 passing a data frame f
  • asp.net网格分页的SQL查询

    我在用iBatis and SQLServer 使用偏移量和限制进行分页查询的最佳方法是什么 也许我添加该列ROW NUMBER OVER ORDER BY Id AS RowNum 但这只会阻止简单查询的数据访问 在某些情况下 我使用选择
  • 为什么要在 C++ 中使用 typedef?

    可以说我有 set
  • 使用 iTextSharp 5.3.3 和 USB 令牌签署 PDF

    我是 iTextSharp 和 StackOverFlow 的新手 我正在尝试使用外部 USB 令牌在 C 中签署 PDF 我尝试使用从互联网上挖掘的以下代码 Org BouncyCastle X509 X509CertificatePar
  • C 中带有指针的结构的内存开销[重复]

    这个问题在这里已经有答案了 我意识到当我的结构包含指针时 它们会产生内存开销 这里有一个例子 typedef struct int num1 int num2 myStruct1 typedef struct int p int num2
  • C++、三元运算符、std::cout

    如何使用 C 用三元运算符编写以下条件 int condition1 condition2 condition3 int double result int or double std cout lt lt condition1 resul
  • 在 Xamarin 中获取 OutOfMemoryException

    java lang OutOfMemoryError 考虑增加 JavaMaximumHeapSize Java 执行时内存不足 java exe 我的 Visualstudio Xamarin 项目出现内存不足异常 请帮助我如何解决此问题
  • 带有私有设置器的 EFCore Base 实体模型属性 - 迁移奇怪的行为

    实体模型继承的类内的私有设置器似乎会导致 EFCore 迁移出现奇怪的问题 考虑以下示例 其中有多个类 Bar and Baz 继承自Foo 跑步时Add Migration多次命令 添加 删除private修饰符 生成的模式在多个方面都是
  • C#中为线程指定特殊的cpu

    我有 2 个线程 我想告诉其中一个在第一个 cpu 上运行 第二个在第二个 cpu 上运行 例如在具有两个 cpu 的机器中 我怎样才能做到这一点 这是我的代码 UCI UCIMain new UCI Thread UCIThread ne

随机推荐