tags:

views:

494

answers:

7
+8  Q: 

How masking works.

Hello,

I am new at C, and I am debugging with source code. However, I am confused with this code snippet.

When the values are assigned to the structure value, I think it is some masking. But not sure, and if it is masking. How does masking work in this concept?

Many thanks,

#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;
+7  A: 

It might help to think of it this way (values shown in binary):

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

So...

1001 is TRANSADDR_ENABLE and MSGINFO_ENABLE
or
1101 is eveything but FASTSTART_CODERS_IN_OFFERED

Does that help at all? The | notation is C syntax to set the correct bit:

int something = 0;
something = MSGINFO_ENABLE | TRANSADDR_ENABLE;

is the a syntax to set only those 2 bits.

marcc
+4  A: 

Read this http://en.wikipedia.org/wiki/Mask_(computing)

adatapost
I'm surprised at the -1... the wikipedia article on this topic is actually quite well written and gives a good explanation. +1
David Claridge
Seconded. This comes across as a "just google it" answer, but the Wikipedia article is a great reference for this topic.
e.James
+2  A: 

The programmer is setting the mask to a certain bit value. In this case:

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

Assuming the code handles messages, when a message comes in they may compare it to this mask to see what is enabled in the message.

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

Notice the "&" operator to do the mask comparisons.

DoxaLogos
+3  A: 

Your variable, msginfo_mask, when represented as a binary number (1's and 0's) is used as a "mask" by setting certain bits to 1 (using bit-wise OR) or clearing certain bits to 0 (using bit-wise AND). Your code snippet sets certain bits to 1 while leaving others unchanged. Masking is comparable to how a painter masks off areas that they do not want to be painted.

If you look at the #defines at the top of your code, you will notice that each number represents a single bit when written out in binary:

#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

Setting bits is done by using the OR function. If you OR a bit with 1, the result is always going to be a 1. If you OR a bit with 0, the original value will not be changed.

So, when you see:

msginfo_mask = MSGINFO_ENABLE | MIME_ENABLE | 
               FASTSTART_CODERS_IN_OFFERED | TRANSADDR_ENABLE;

What you are saying is "take the value of msginfo_mask and OR it with (binary) 0001, 0010, 0100, and 1000. This is the same thing as saying "set bit 0, bit 1, bit 2, and bit 3."

Robert Cartaino
+13  A: 

Ok in plain English:

The Hexdecimal numbers 0x01,0x02,0x04,0x08 were each selected BECAUSE they are each encoded as different single bits being set in binary. None of the bit maps overlap so each one can be read and set without being effected by the other bits. Adding the following comments to your code makes it clearer what's happening:

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

Now adding a comment before the other line shows the result:

// 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;

While the comments on the assignment make it clear what's going on, once you understand what's happening, the comments kinda defeat the purpose of symbolically defining constants.

NoMoreZealots
Hello, I understand a bit better after reading all the other answers. Using a mask in this instance is like setting the variables or MSGINFO_ENABLE, MINE_ENABLE, etc. So setting all of them you are enabling them all to be true. So for example, if I just wanted to have TRANSADDR_ENABLE enabled, I would just have done this: VirtBoard.msginfo_mask = TRANSADDR_ENABLE; Which would equal 8. However, would this be the same if I was to have all these a global variables and set them all to either true or false, depending on which ones I wanted enabled or not?
robUK
Using Bitmaps allows you to pack them all into a single word, or in this case a nybble. If you have hardware or other software that is expecting them packed into a bitmap, separating them into multiple variables will be incompatable. If you control both sides of the code then you could make them globals, however generally speaking globals are typically avoided in favor of passing references to structures.
NoMoreZealots
RobUK: each bit is like a switch. By OR-ing multiple values together, you get one mask which determines the switches that do get set, and you can write them in one action. If you have 32 of these switches you may need up to 4 billion globals to cover each possible combination, whereas you'd need only 32 bit masks to individually address each bit.
Adriaan
You would never need 4 billion globals, each global variable would be a bool that could be on or off, you would need at most 32 globals.
Ron Warholic
+2  A: 

The other part is that "or" the masks together are probably being used as switches to enable/disable certain fuctionality. In the examples you have written, it looks like possibly output at different levels or parts of the codes.

The defined masks can be used to check the functionality to see if it is enable or disabled. For example:

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");
}

In the first if, since MSGINFO_ENABLED mask was "or" and assigned to the variable, when you apply an "and" operation with the variable and MSGINOF_ENABLED mask, a non zero value is returned, indicating it is true. So the printf statement will be executed.

In the case of the second if, since TRANSADDR_ENABLE was not "or" in to the variable, when an "and" is used with the variable and TRANSADDR_ENABLE mask, it will return a zero value, so no message will be printed.

Glenn
+2  A: 

The binary operator '|' is the bitwise-or operator; for each bit in the two input words, if either bit is a 1, then the corresponding bit in the result is a 1:

0001 | 0010 = 0011

The '|' operator is typically used to set individual bits in a word, such as in the code snippet you posted.

The binary operator '&' is the bitwise-and operator; for each bit in the two input words, if both bits are 1, then the corresponding bit in the result is a 1:

0101 & 0110 = 0100

The '&' operator can be used to test if a bit is set. For example, to test if the MSGINFO_ENABLE bit is set, you'd do something like

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

The expression

VirtBoard.msginfo_mask & MSGINFO_ENABLE

will evaluate to 1 (0x0001) if the MSGINFO_ENABLE bit was set,0 otherwise.

The unary operator '~' is the bitwise-not operator; for each bit in the input word, the corresponding bit in the result is set to the opposite value:

~ 0001 = 1110

You can use the '~' operator together with the '&' operator to clear an individual bit. For example, if we wanted to clear the MSGINFO_ENABLE bit, we'd do something like

VirtBoard.msginfo_mask = VirtBoard.msginfo_mask & ~MSGINFO_ENABLE;

which can be shortened to

VirtBoard.msginfo_mask &= ~MSGINFO_ENABLE;

Negating MSGINFO_ ENABLE gives us 1111111111111110 (assuming a 16-bit unsigned int); since the leading bits are all 1, and-ing this against the VirtBoard.msginfo_ mask preserves any bits that are already set; i.e., 0000000000001111 & 1111111111111110 = 0000000000001110.

If we wanted to clear both the MSGINFO _ENABLE and TRANSADDR _ENABLE bits, we'd combine all the operators like so:

VirtBoard.msginfo_mask &= ~(MSGINFO_ENABLE | TRANSADDER_ENABLE)
John Bode
Very good example.
robUK