0

我正在维护一个包含未知逻辑的遗留 c 代码。显然它与 unsigned char 的按位运算有关。但是我不熟悉按位运算,有人可以解释一下这背后的机制吗?我包括了一些关键陈述。

    private const unsigned char DONE_HDR = 0x01;
    private const unsigned char DONE_TRL = 0x02;
    private const unsigned char DONE_ACC = 0x04;
    private const unsigned char DONE_NTW = 0x08;
    unsigned char done = 0;

它分配给变量的是什么?16位数字?

case TAP_HDR:
    if (done & DONE_HDR){
        //do something
    }
    done |= DONE_HDR;
    break;
case TAP_TRL:
    if (done & DONE_TRL){
        //do something
    }
    done |= DONE_TRL;
    break;
case TAP_ACC:
    if (done & DONE_ACC){
        //do something
    }
    done |= DONE_ACC;
    break;
case TAP_NTW:
    if (done & DONE_NTW){
        //do something
    }
    done |= DONE_NTW;
    break;

如何评估 unsigned char?我以为我们只能评估布尔值或数字。如果数字为正,则将其评估为真。但是 unsigned char 没有负值,所以我在这里感到困惑。什么时候会是真的?“&”操作的目的/结果是什么?

如果在那之后,无论上面的 if 语句是否为真,它都会:

done |= DONE_HDR;

似乎正在记录状态。我想它产生的任何东西都必须取决于“完成”的值,因为 DONE_HDR 是一个常数。

最后检查:

if (!(done & DONE_HDR))
if (!(done & DONE_TRL))
if (!(done & DONE_ACC))
if (!(done & DONE_NTW))

可能正在检查它是否遇到了所有记录。再一次,我不知道 & 在这里是如何发挥作用的。

4

3 回答 3

4
  1. &是按位与运算符。所以表达式如下:

    (done & MASK)
    

    正在检查该MASK位是否设置在done. 这意味着:

    !(done & MASK)
    

    正在检查是否MASK已清除。赋值运算符行:

    done |= MASK;
    

    正在设置中的MASKdone

  2. char和是整数类型signed charunsigned char就像任何其他整数类型一样——它们通常更小。大多数情况下,它们是 8 位类型,但您可以检查CHAR_BITstdint.h以确定。

于 2012-09-06T04:26:09.947 回答
3

首先,private不是 C 关键字。我猜一些头文件#define-s 它到某个属性或其他编译器特定的扩展名(或者可能是static

在几乎所有 C 实现中,achar或是unsigned char一个字节(8 位)。普通char类型可以是有符号的或无符号的(这个重要的选择取决于实现,通常是特定于体系结构的;在一些编译器(如 GCC)上,它可以通过编译器选项进行配置)。无符号字符通常是无符号字节(值从 0 到 0xff)。有符号字符通常是有符号字节(从 -128 到 +127)。

名称DONE_HDR等被定义为const优化编译器可以对它们进行常量折叠。

您的代码只是测试done(使用 eg done & DONE_HDR)中的位字段并更新该变量(使用 设置该位done |= DONE_HDR)。

于 2012-09-06T04:26:35.897 回答
2

在 C 中,除 0 以外的每个整数都被认为是真,而 0 是假。

char 也被认为是 ASCII 字符及其数值。

& 运算符执行按位与,这意味着逐位比较,例如 0x01 将与 0x01 组合得到 0x01 的结果,而 0x01 & 0x03 将得到 0x01 而 0x01 & 0x02 将得到 0x00 .

这可以说明:

0x01 以位为单位:00000001
0x03 以位为单位:00000011
0x01& 0x03:00000001

0x01: 00000001
0x02: 00000010
0x01 & 0x02: 00000000

类似的情况是 | 这是按位或运算符,这意味着它正在根据底层位进行或运算,这意味着 0x01 | 0x02 结果为 0x03,因为

0x01:00000001
0x02:00000010
0x01 | 0x03: 00000011

将这些与 && 和 || 进行对比 它们仅进行逻辑比较,这在 C 中本质上意味着 0x01 和 0x02 被转换为真,然后进行比较,结果为真。

另请注意,按位运算符不会短路,而逻辑会短路,原因是按位我们需要比较整个值,而对于逻辑比较,一个值可能足以知道结果。

我还没有遇到过 |= 运算符,但我猜它是 done = done | 的简写。面具; 这基本上导致 MASK 中为 1 的位将在完成时设置为 1。

(熟悉 VB 的读者注意:大多数 VB 程序员可能不知道,但 VB 关键字 AND\OR\NOT 实际上是按位与,VB6 中没有逻辑与,但在 VB.Net 中有 AndAlso 运算符,并且结果(1和2)在VB中实际上是错误的,因为它是按位的,这也是VB中没有短路评估的原因,这在处理Win32API时也会产生影响,因为不做返回 1 的 API 函数实际上是 -1,这也是正确的,而不是逻辑 NOT。)

于 2012-09-06T04:36:53.160 回答