Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/72.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C “优化”;i=b?(i“面具):(i“面具”);_C_Bit Manipulation_Ternary Operator - Fatal编程技术网

C “优化”;i=b?(i“面具):(i“面具”);

C “优化”;i=b?(i“面具):(i“面具”);,c,bit-manipulation,ternary-operator,C,Bit Manipulation,Ternary Operator,我希望能够设置或清除uintX\u t t的(多个)位 i是一个运行时变量(uintX\u t)。 b是一个运行时变量(uintX\u t),它被限制为0或1 mask是编译时常量 有没有比以下更好的方法: i = b ? (i | mask) : (i & ~mask) 如果可能的话,我希望避免分支。目标是ARM,如果有关系的话。这里的想法是用乘法替换分支,我们可以根据b的值将每边归零: i = (i | (mask * b)) & (~mask | (mask * b));

我希望能够设置或清除
uintX\u t t
的(多个)位

i
是一个运行时变量(
uintX\u t
)。
b
是一个运行时变量(
uintX\u t
),它被限制为
0
1

mask
是编译时常量

有没有比以下更好的方法:

i = b ? (i | mask) : (i & ~mask)

如果可能的话,我希望避免分支。目标是ARM,如果有关系的话。

这里的想法是用乘法替换分支,我们可以根据b的值将每边归零:

i = (i | (mask * b)) & (~mask | (mask * b));

另一种选择:始终将位设置为0(左部分),并可选择将位设置为1(右部分)


利用
-1u
是设置了所有位的值这一事实:

i = (i & ~mask) | (mask & -b);


第二种方法减少了操作数量和代码大小。第一种方法在超标量体系结构上可能会更快,因为有些操作可以并行执行。

最可读的方法是分几个步骤执行,这样做不会影响性能,但会提高可读性

与位运算符的情况一样,必须小心隐式类型提升。例如,不小心使用
~
往往会产生隐式的升级错误。(操作符
?:
也会通过平衡第二个和第三个操作数来静默提升结果。)

可读、可移植、安全的代码:

uintx_t i = ... ;
uintx_t b = ... ;  // 1 or 0

i &= (uintx_t)~mask;   // always clear the bit
i |= mask * b;         // if b is 1, set the bit, otherwise OR with 0

i=b
i==b
?@HongOoi
i=(b?(i | mask):(i&~mask))
我用Java测试过,如果你愿意,我可以用Java发布测试代码,显示它确实有效现在的问题是:性能损失、分支或乘法方面有什么更糟糕?在我的测试中,我使用了i=101(二进制),mask=110(二进制)您可以很容易地发现,添加两个代码并分别运行100万次,然后测量时间。您可以简单地将乘法重写为一个求反和一个按位的乘法,如果乘法速度较慢(通常值得这样重写)这也源自Guilherme的答案,并使用该答案或分布在and@harold你的评论是不是偶然遗漏了什么?它的结尾看起来很奇怪。不,我只是没有清楚地格式化它,我的意思是,或者在上面分发,而
-b
-1u
不是一回事。如果
b
是任何有符号的小整数类型,则会暂时以负数结束。与
-1u
不同,1u始终是正数。在这种特殊情况下,这不会是一个问题,但在像
(mask&-b)@Lundin这样的代码中会是灾难性的。对,如果
b
int
窄,并且平台不使用二的补码,那么我的答案中的代码实际上有问题。在这种情况下,需要一个额外的cast
-(unsigned)b
。谢谢,我喜欢这种可读的方法。如果
i
是AVR上的PORTA,这会导致GPIO故障吗?还是在编译过程中这两条语句合并为一条?我希望PORTA被标记为volatile以阻止这种情况发生。@chrisdew它会导致GPIO在几个时钟周期内变低。不允许编译器优化代码,因为
PORTA
将是一个易失性寄存器。但在某些硬件上,GPIO端口可能需要一些时钟信号来稳定。
i ^= (i ^ -b) & mask;
uintx_t i = ... ;
uintx_t b = ... ;  // 1 or 0

i &= (uintx_t)~mask;   // always clear the bit
i |= mask * b;         // if b is 1, set the bit, otherwise OR with 0