简化 C 中的二进制和异或

Posted

技术标签:

【中文标题】简化 C 中的二进制和异或【英文标题】:Simplify binary and and xor in C 【发布时间】:2021-04-22 19:06:37 【问题描述】:

有没有办法简化C中的以下表达式?

result = (constant & value) ^ value;

用例是:

#define ALL_SENSORS = (BIT(0) + BIT(1) + BIT(2) + BIT(19))  # = 524295

static int get_invalid_sensors(int sensor_mask) 
    return (ALL_SENSORS & sensor_mask) ^ sensor_mask;

是否可以将二进制操作简化为一个,所以我不需要调用sensor_mask两次?

【问题讨论】:

编译器擅长常量折叠,所有的编译时常量表达式都可以由编译器自己计算,只有结果会出现在生成的代码中。编译器还可以生成重用先前计算结果的代码,特别是如果它可以推断它不会在两者之间发生变化(常量永远不会)。因此,请在启用优化的情况下进行构建,并查看生成的代码。我相信它会尽可能地达到最佳状态。 @Someprogrammerdude:sensor_mask 是一个变量,所以您所说的某些内容并不完全正确!我能想到的只有'ALL_SENSORS & (~sensor_mask)' 作为优化的一般规则:你几乎不值得做这样的低级微优化。编译器几乎总是会做得更好。更不用说手写的优化往往晦涩难懂,难以阅读、理解和维护。如果您遇到性能问题,请分析优化的构建,并专注于最重要的两个(或者可能是三个)瓶颈。 ALL_SENSORS 是常量吗?例如,BIT(x) 只是 (1 << (x)),而不是像函数调用或包含 sensor_mask 的宏这样的奇怪东西? 使用int 进行按位运算几乎肯定是错误的,因此您可能想用uint32_t 等替换它。 【参考方案1】:

(~ALL_SENSORS & sensor_mask)怎么样?

【讨论】:

这不太一样!如果 ALL_SENSORS 是 0x0f 并且 sensor_mask 是 0x08 那么这将返回 0 而不是 0x07! @Skizz (0x0f & 0x08) ^ 0x08 为 0。 哎呀,脑放屁时刻!那么它不总是0吗? @Skizz 或者在真值表中,((0 & 0) ^ 0) == 0((0 & 1) ^ 1) == 1((1 & 0) ^ 0) == 0((1 & 1) ^ 1) == 0。与(~0 & 0) == 0(~0 & 1) == 1(~1 & 0) == 0(~1 & 1) == 0 进行比较。它们是一样的。 @Skizz 不,它并不总是 0。例如如果sensor_mask 是 54321,那么结果就是 54320。【参考方案2】:

如果你把这个(或至少类似的)代码放入here。然后你可以看到优化的代码,例如 RISC-V 是

get_invalid_sensors: # @get_invalid_sensors
  not a0, a0
  and a0, a0, a1
  ret

从这里你可以意识到(~ALL_SENSORS & sensor_mask) 已经足够了。但您也可以意识到编译器很可能无论如何都能够优化您的代码。

【讨论】:

【参考方案3】:

表达式(ALL_SENSORS & sensor_mask) ^ sensor_mask 的目标是屏蔽sensor_mask 中不在ALL_SENSORS 中的所有位。您也可以通过~ALL_SENSORS & sensor_mask 进行此操作。

【讨论】:

以上是关于简化 C 中的二进制和异或的主要内容,如果未能解决你的问题,请参考以下文章

计算机中的二进制运算

C语言重点难点:与,或和异或

2018-2019-1 20165206 《信息安全系统设计基础》第2周学习总结

HDU6129 规律

不用加减乘除做加法

位运算