【问题标题】:Order of arguments for C bitwise operations?C按位运算的参数顺序?
【发布时间】:2020-06-29 05:34:00
【问题描述】:

我已经让一个软件运行起来,现在我正在尝试对其进行调整以使其运行得更快。我也发现了一些令人震惊的东西——只是很奇怪。它不再相关,因为我切换到使用指针而不是索引数组(使用指针更快),但我仍然想知道发生了什么。

代码如下:

short mask_num_vals(short mask)
{
        short count = 0;

        for(short val=0;val<NUM_VALS;val++)
                if(mask & val_masks[val])
                        count++;
        return count;
}

这小段代码被多次调用。真正让我惊讶的是,这段代码的运行速度明显快于其前身,后者只是将“&”操作的两个参数颠倒过来。

现在,我原以为这两个版本在所有实际目的上都是相同的,而且它们确实产生了相同的结果。但是上面的版本更快——明显更快。它在使用它的整个代码的运行时间上产生了大约 5% 的差异。我尝试测量在上述函数中花费的时间量完全失败了 - 测量所用时间远远超过实际执行其余代码的时间。 (我猜是海森堡软件原理的一个版本。)

所以我的图片是,编译后的代码评估这两个参数,然后对它们进行按位“与”。谁在乎论点的顺序?显然编译器或计算机会这样做。

我完全不支持的猜想是编译后的代码必须为每个位评估“val_masks[val]”。如果“val_masks[val]”首先出现,它会为每一位评估它,如果“mask”首先出现,那么如果“mask”中的特定位为零,它就不会打扰“val_masks[val]”。我没有任何证据支持这个猜想;我只是想不出任何其他可能导致这种行为的东西。

这看起来有可能吗?这种行为对我来说似乎很奇怪,我认为这表明我对编译代码的工作方式和实际工作方式的看法有所不同。同样,不再那么相关了,因为我进一步改进了代码(使用指针而不是数组)。但我仍然想知道是什么原因造成的。

硬件是 Apple MacBook Pro 15 英寸 2018,MacOS 10.15.5。软件为 gcc 编译器,“gcc --version”产生如下输出。

Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/4.2.1
Apple clang version 11.0.3 (clang-1103.0.32.62)
Target: x86_64-apple-darwin19.5.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

使用命令“gcc -c -Wall 'C filename'”编译,与“gcc -o -Wall 'object filenames'”链接。

【问题讨论】:

  • 尝试使用gcc -O2编译这两个版本的代码,看看汇编没有区别。
  • 几个问题:您使用的编译标志是什么? NUM_VALS 的值是多少? val_masks[] 中的掩码是什么?这个数组是如何定义的?
  • 你可以用gcc -S编译来查看程序集。
  • 阅读更多关于GCC的信息。您想使用gcc -Wall -O3 -S -fverbose-asm。实际上,您使用 Clang 您应该阅读其文档。另请阅读 C11 标准 n1570 解释可以进行哪些优化
  • "我切换到使用指针而不是索引数组(使用指针更快)," - 这并不普遍。它更可能反映了您在编译代码时没有设置优化级别的事实——或者您有其他问题。编译器完全能够像使用指针一样优化索引。

标签: c operator-precedence bitwise-and


【解决方案1】:

代码优化器通常是不可预测的。在对代码进行小的无意义调整之后,或者在更改命令行选项之后,或者在升级编译器之后,它们的输出可能会改变。你不能总是解释为什么编译器在一种情况下做了一些优化,而在另一种情况下却没有;你可以猜到所有你想要的,但只有经验才能显示出来。

确定正在发生什么的一种强大技术:将您的两个版本的代码转换为汇编语言并进行比较。

GCC 可以是 invoked,带有命令行开关 -S

gcc -S -Wall -O -fverbose-asm your-c-source.c

从 C 文件 your-c-source.c 生成文本汇编文件 your-c-source.s(您可以使用 less 之类的寻呼机或 GNU emacs 之类的源代码编辑器查看它)

Clang 编译器有类似的选项。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-20
    • 2015-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多