掩蔽是如何工作的

时间:2009-08-07 02:24:01

标签: c++ c

我是C的新手,我正在使用源代码进行调试。但是,我对此代码段感到困惑。

当将值分配给结构值时,我认为它是一些掩蔽。但不确定,如果它是掩盖的。屏蔽如何在这个概念中发挥作用?

非常感谢,

#define MSGINFO_ENABLE                   0x01
#define MIME_ENABLE                      0x02
#define FASTSTART_CODERS_IN_OFFERED      0x04
#define TRANSADDR_ENABLE                 0x08

typedef struct {

    unsigned int    msginfo_mask;     /* added in version 0x0101               */

} VIRTBOARD; 


VIRTBOARD       VirtBoard;

/* Not sure I understand what is happening here. */
VirtBoard.msginfo_mask  = MSGINFO_ENABLE | MIME_ENABLE | FASTSTART_CODERS_IN_OFFERED | TRANSADDR_ENABLE;

6 个答案:

答案 0 :(得分:16)

用简单的英语说好:

每个选择十六进制数0x01,0x02,0x04,0x08,因为它们每个都被编码为以二进制设置的不同单个位。没有位图重叠,因此每个位图都可以被读取和设置而不受其他位的影响。在代码中添加以下注释可以更清楚地了解正在发生的事情:

#define MSGINFO_ENABLE                   0x01  // => 0001
#define MIME_ENABLE                      0x02  // => 0010
#define FASTSTART_CODERS_IN_OFFERED      0x04  // => 0100
#define TRANSADDR_ENABLE                 0x08  // => 1000

现在在另一行之前添加注释会显示结果:

// VirtBoard.msginfo_mask |= 0001 
// VirtBoard.msginfo_mask |= 0010 
// VirtBoard.msginfo_mask |= 0100 
// VirtBoard.msginfo_mask |= 1000
//                           ----
// VirtBoard.msginfo_mask == 1111
VirtBoard.msginfo_mask = MSGINFO_ENABLE              |
                         MIME_ENABLE                 |
                         FASTSTART_CODERS_IN_OFFERED |
                         TRANSADDR_ENABLE;

虽然对作业的评论清楚地表明发生了什么,但一旦你理解了正在发生的事情,评论就会失去象征性地定义常数的目的。

答案 1 :(得分:7)

以这种方式思考它可能会有所帮助(以二进制显示的值):

MSGINFO_ENABLE = 0001
MIME_ENABLE = 0010
FASTSTART_CODERS_IN_OFFERED = 0100
TRANSADDR_ENABLE = 1000

因此...

1001是TRANSADDR_ENABLEMSGINFO_ENABLE

1101是eveything但FASTSTART_CODERS_IN_OFFERED

这有帮助吗? |表示法是用于设置正确位的C语法:

int something = 0;
something = MSGINFO_ENABLE | TRANSADDR_ENABLE; 

是仅设置这2位的语法。

答案 2 :(得分:4)

您的变量msginfo_mask,当表示为二进制数(1和0)时,通过将某些位设置为1(使用按位OR)或将某些位清零(0),将其用作“掩码”(使用逐位AND)。您的代码段将某些位设置为1,而其他位保持不变。掩蔽与画家如何遮盖他们不想画的区域相当。

如果查看代码顶部的#defines,您会注意到当以二进制写出时,每个数字代表一位:

#define MSGINFO_ENABLE                   0x01    <--  0001 in binary
#define MIME_ENABLE                      0x02    <--  0010 in binary
#define FASTSTART_CODERS_IN_OFFERED      0x04    <--  0100 in binary
#define TRANSADDR_ENABLE                 0x08    <--  1000 in binary

使用OR功能完成设置位。如果OR为1,则结果总是为1.如果OR为0,则原始值不会改变。

所以,当你看到:

msginfo_mask = MSGINFO_ENABLE | MIME_ENABLE | 
               FASTSTART_CODERS_IN_OFFERED | TRANSADDR_ENABLE;

你所说的是“取msginfo_mask的值并将其与(二进制)0001,0010,0100和1000一起使用。这与说”设置位0,位1,位相同2,和第3位。“

答案 3 :(得分:3)

二元运算符'|'是按位运算符;对于两个输入字中的每个位,如果任一位为1,则结果中的相应位为1:

0001 | 0010 = 0011

'|'运算符通常用于设置单词中的各个位,例如在您发布的代码段中。

二元运算符'&amp;'是按位和运算符;对于两个输入字中的每个位,如果两个位都为1,则结果中的相应位为1:

0101 & 0110 = 0100

'&amp;'运算符可用于测试是否设置了位。例如,要测试MSGINFO_ENABLE位是否已设置,您可以执行类似

的操作
if (VirtBoard.msginfo_mask & MSGINFO_ENABLE != 0)
{
  /* MSGINFO_ENABLE bit is set, do something interesting */
}

表达式

VirtBoard.msginfo_mask & MSGINFO_ENABLE 
如果MSGINFO_ENABLE位置1,

将评估为1(0x0001),否则为0。

一元运算符'〜'是按位运算符;对于输入字中的每个位,结果中的相应位设置为相反的值:

~ 0001 = 1110

您可以将'〜'运算符与'&amp;'一起使用运算符清除单个位。例如,如果我们要清除MSGINFO_ENABLE位,我们会执行类似

的操作
VirtBoard.msginfo_mask = VirtBoard.msginfo_mask & ~MSGINFO_ENABLE;

可以缩短为

VirtBoard.msginfo_mask &= ~MSGINFO_ENABLE;

否定MSGINFO_ ENABLE给我们1111111111111110(假设一个16位无符号整数);因为前导位都是1,所以对着VirtBoard.msginfo_掩码保留任何已经设置的位;即,0000000000001111&amp; 1111111111111110 = 0000000000001110。

如果我们想清除MSGINFO _ENABLE和TRANSADDR _ENABLE位,我们将所有运算符组合起来:

VirtBoard.msginfo_mask &= ~(MSGINFO_ENABLE | TRANSADDER_ENABLE)

答案 4 :(得分:2)

程序员将掩码设置为某个位值。在这种情况下:

VitBoard.msginfo_mask = 0x01 | 0x02 | 0x04 = 0x07

假设代码处理消息,当消息进入时,他们可以将其与此掩码进行比较,以查看消息中启用的内容。

if((newMsg & VitBoard.msginfo_mask) == 0x07)
{
  //do something related to mime enable, msginfo enable and faststart
}

注意“&amp;”操作员进行掩码比较。

答案 5 :(得分:2)

另一部分是“或”掩模在一起可能被用作开关以启用/禁用某些功能。在您编写的示例中,它看起来可能在不同级别或部分代码中输出。

定义的掩码可用于检查功能,以查看它是启用还是禁用。例如:

VirtBoard.msginfo_mask = MSGINFO_ENABLE | MIME_ENABLE ;
if ( VirtBoard.msginfo_mask & MSGINFO_ENABLE )  
{
  printf("Messages enabled\n";
}

if ( VirtBoard.msginfo_mask & TRANSADDR_ENABLE) 
{
  printf("Transaddress enabled\n");
}

在第一个if中,由于MSGINFO_ENABLED掩码是“或”并分配给变量,当您使用变量和MSGINOF_ENABLED掩码应用“和”操作时,将返回非零值,表示它为true。所以printf语句将被执行。

对于第二个if,由于TRANSADDR_ENABLE不是“或”变量,当“和”与变量和TRANSADDR_ENABLE掩码一起使用时,它将返回零值,因此不会打印任何消息