清除并测试C语言中的位(Bit)可以在单个语句中完成。

huangapple go评论65阅读模式
英文:

clear and test bit in single statement in C

问题

status = (number & BIT(27)) ? (number & ~BIT(27)) : (number & BIT(27));
英文:

I would like to clear, and test a particular bit in single statement, for instance to clear bit 27 and test the same bit, and wanted to return the status for same:

{
    status = number & BIT(27);

    if (status)
        number & ~BIT(27);

    return number & BIT(27);
}

Is there way to do it using Ternary operator ?

答案1

得分: 3

该代码片段不修改 `number`,因此它将返回位值,但不会清除它。您可能是想要这样做:

#define BIT(n) (1U << (n)) // 假设这是 BIT 或类似的定义

{
status = number & BIT(27);

if (status)
    number &= ~BIT(27);

return status;

}


您确实可以在单个表达式中使用三元运算符和逗号表达式来实现这一点:
return (number & BIT(27)) ? (number &= ~BIT(27), BIT(27)) : 0;
或者这个替代方法:
return (number & BIT(27)) ? (number ^= BIT(27), BIT(27)) : 0;

在测试表达式的评估和第二个或第三个表达式的评估之间存在一个序列点,所以以这种方式修改 `number` 是可以的。

这种方法可能允许您在一个表达式宏内封装测试和清除技巧,但请注意,这个宏会对 `number` 进行两次评估。您可以考虑使用一个接受 `number` 地址的内联函数:

static inline int test_and_clear27(int *number) {
if (*number & BIT(27)) {
*number &= ~BIT(27);
return BIT(27);
} else {
return 0;
}
}

或者无需分支:

static inline int test_and_clear27(int *number) {
int status = *number & BIT(27);
*number &= ~BIT(27);
return status;
}


这些方法不是线程安全的:它不能用于实现信号量,因为测试和清除操作是分开的,不是原子的。
英文:

The code fragment does not modify number so it will return the bit value but not clear it. You probably meant this instead:

#define BIT(n)  (1U &lt;&lt; (n))  // assuming this definition for BIT or similar

{
    status = number &amp; BIT(27);

    if (status)
        number &amp;= ~BIT(27);

    return status;
}

You can indeed achieve this in a single expression using the ternary operator and a comma expression:

    return (number &amp; BIT(27)) ? (number &amp;= ~BIT(27), BIT(27)) : 0;

or this alternative:

    return (number &amp; BIT(27)) ? (number ^= BIT(27), BIT(27)) : 0;

There is a sequence point between the evaluation of the test expression and the evaluation of the second or third expression, so it is OK to modify number this way as a side effect.

This approach may allow you to encapsulate the test and clear trick inside an expression macro, but be aware that this macro would evaluate number twice. You might consider an inline function taking the address of number:

static inline int test_and_clear27(int *number) {
    if (*number &amp; BIT(27)) {
        *number &amp;= ~BIT(27);
        return BIT(27);
    } else {
        return 0;
    }
}

Or without branches:

static inline int test_and_clear27(int *number) {
    int status = *number &amp; BIT(27);
    *number &amp;= ~BIT(27);
    return status;
}

These methods are not thread safe: it cannot be used to implement semaphores as the test and clear operations are separate and do not happen atomically.

答案2

得分: 2

Your current code does not do what your description claims. Instead, it is equivalent to

return number & BIT(27);

— A nice, concise, single statement.

However, assuming that you actually do wanted to clear bit 27, the following code does that (the if in your code is unnecessary):

status = number & BIT(27);
number &= ~BIT(27);
return status;

There’s really no good reason to rewrite this as a single statement (except by encapsulating it inside a function1). But, just for argument’s sake, it is possible. chqrlie has already posted an answer, but if you only use status as a boolean flag you can shorten the code and remove the conditional operator:

return (number & BIT(27)) && (number &= ~BIT(27), 1);

Is this better than the three-statement solution? Absolutely not! On the contrary: it introduces a branch into the logic which, if anything, makes this code slower.


1 And as per Ian Abbott’s comment the Linux kernel provides just such a function: test_and_clear_bit(), but be careful since it requires to have a variable of unsigned long type and any casting to it is a very bad idea.

英文:

Your current code does not do what your description claims. Instead, it is equivalent to

return number &amp; BIT(27);

— A nice, concise, single statement.

However, assuming that you actually do wanted to clear bit 27, the following code does that (the if in your code is unnecessary):

status = number &amp; BIT(27);
number &amp;= ~ BIT(27);
return status;

There’s really no good reason to rewrite this as a single statement (except by encapsulating it inside a function<sup>1</sup>). But, just for argument’s sake, it is possible. chqrlie has already posted an answer, but if you only use status as a boolean flag you can shorten the code and remove the conditional operator:

return (number &amp; BIT(27)) &amp;&amp; (number &amp;= ~ BIT(27), 1);

Is this better than the three-statement solution? Absolutely not! On the contrary: it introduces a branch into the logic which, if anything, makes this code slower.


<sup>1</sup> And as per Ian Abbott’s comment the Linux kernel provides just such a function: test_and_clear_bit(), but be careful since it requires to have a variable of unsigned long type and any casting to it is a very bad idea.

huangapple
  • 本文由 发表于 2023年2月6日 17:18:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/75359371.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定