...

View Full Version : MS combined constants: How do they do that?



codegoboom
11-29-2004, 09:40 AM
Interdependent props... Is this a programming technique documented somewhere, or a trade secret?

For example, the buttons argument for the VBS MsgBox Function:

The first group of values (05) describes the number and type of buttons displayed in the dialog box; the second group (16, 32, 48, 64) describes the icon style; the third group (0, 256, 512, 768) determines which button is the default; and the fourth group (0, 4096) determines the modality of the message box. When adding numbers to create a final value for the argument buttons, use only one number from each group.

Wtf is going on in that black box? :D

shmoove
11-29-2004, 10:22 AM
They are using separate bits out of the number. It's called sometimes bitmasks or bitfields.

For example, I have one byte and I want to store three properties in it: the first property has 3 choices, the second 4 choices and the third has 3.
Since the first property has 3 options, 1 bit isn't enough (that's only 0 or 1, so two choices). With two bits I can store 4 options (00,01,10,11), so that's enough so the first two bits represent the first property. The second property has 4 options, so thats also 2 bits, so bits 3 and 4 represent the second property. The third property only needs to choices so 1 bit is enough, bit 5.
The first two bits in binary represent 1 and two, so my first property is saved with 0,1 and two. Bits 3 and 4 represent 4 and 8 (remember, we are talking about powers of 2), so the choices are 0, 4, 8, 12 (4 + 8). The fifth bit represents 16, so we use 0 and 16. Then you can add these properties up and store them in one byte without having any conflicts between the properties, since every number will affect different bits.

shmoove

Spookster
11-29-2004, 12:59 PM
It's called packing bits. You can pack 8 bits into a byte. If you are only working with boolean values this is very handy. We use that technique at work to pass values back and forth between various pieces of our software that are running on different unix and vxworks systems. It is useful for real time systems where you need things to be as fast as possible.

As schmoove suggested you can use a bitmask to identify a specific bit or set of bits. You can pack values other than just boolean values. You just need to make sure that you keep track of which bits go where.

codegoboom
11-30-2004, 05:20 PM
How very interesting... thanks. :)

So how would you guys go about unpacking the "buttons" bitfield with a bitmask?


I was trying imagine it in javascript :D, but uh... this is the only way I got it to work:

<body>
<script type="text/javascript">
function unpack(buttons)
{
var
bits = buttons.toString(2).split(""),
n = bits.length,
nibble = 4,
dec = 0;
buttons = [];
while(n--)
{
dec += +bits.shift() * Math.pow(2, n);
if(n % nibble)
continue;
buttons.push(dec >> n);
dec = 0;
}
switch(buttons.pop())
{
case 1:
alert("jsOKCancel");
break;
case 2:
alert("jsAbortRetryIgnore");
break;
case 3:
alert("jsYesNoCancel");
break;
case 4:
alert("jsYesNo");
break;
case 5:
alert("jsRetryCancel");
break;
default:
alert("jsOKOnly");
}
switch(buttons.pop())
{
case 1:
alert("jsCritical");
break;
case 2:
alert("jsQuestion");
break;
case 3:
alert("jsExclamation");
break;
case 4:
alert("jsInformation");
break;
}
switch(buttons.pop())
{
case 1:
alert("jsDefaultButton2");
break;
case 2:
alert("jsDefaultButton3");
break;
case 3:
alert("jsDefaultButton4");
break;
default:
alert("jsDefaultButton1");
}
switch(buttons.pop())
{
case 1:
alert("jsSystemModal");
break;
default:
alert("jsApplicationModal");
}
}
</script>
<form>
<fieldset>
<legend>Pack</legend>
<label>Group 1: </label>
<select name="G1">
<option value="0"selected>jsOKOnly</option>
<option value="1">jsOKCancel</option>
<option value="2">jsAbortRetryIgnore</option>
<option value="3">jsYesNoCancel</option>
<option value="4">jsYesNo</option>
<option value="5">jsRetryCancel</option>
</select>
<hr>
<label>Group 2: </label>
<select name="G2">
<option value="0" selected>(none)</option>
<option value="16">jsCritical</option>
<option value="32">jsQuestion</option>
<option value="48">jsExclamation</option>
<option value="64">jsInformation</option>
</select>
<hr>
<label>Group 3: </label>
<select name="G3">
<option value="0" selected>jsDefaultButton1</option>
<option value="256">jsDefaultButton2</option>
<option value="512">jsDefaultButton3</option>
<option value="768">jsDefaultButton4</option>
</select>
<hr>
<label>Group 4: </label>
<select name="G4">
<option value="0" selected>jsApplicationModal</option>
<option value="4096">jsSystemModal</option>
</select>
</fieldset>
<input type="button" value="Unpack"
onclick="unpack(
+(G1.options[G1.selectedIndex].value) | +(G2.options[G2.selectedIndex].value) |
+(G3.options[G3.selectedIndex].value) | +(G4.options[G4.selectedIndex].value)
)">
</form>
</body>

shmoove
11-30-2004, 06:16 PM
Most languages have bit shifting operators and bitwise logical operators that can do that. A bitwise logical operator is like the normal logical operators (AND, OR, NOT, etc.), but it works on every bit separately. In C/C++/Java (I think Javascript too) the logical operators are & for AND (as opposed to && for the normal AND), | for OR, ~ for NOT, ^ for XOR. Bitshift operators are << and >>.
Some samples:


a = 10001011
~a = 01110100
b = 00111101
a | b = 10111111
a & b = 00001001

Using these operators you can easily extract the "fields" in a bitfield. For instance, if you want to extract bits 3 and 4 from n:


// bits 3 and 4 -> 00001100 binary -> 12 decimal, so
flag = n & 12;


shmoove

codegoboom
11-30-2004, 07:17 PM
Alrighty then... you know, I think my simple mind has twiddled one too many bits for the time being, so I'll look back on this later, maybe. ;)

codegoboom
12-01-2004, 05:41 AM
Ok, I got it, hopefully... :rolleyes:

The nibbles have to be tested in descending order--to handle dependent bits (like 1,3,5)...

and if a field exists, then "n AND field" will equal "field".


So:

function unpack(n)
{
switch(true)
{
case (n & 5) == 5:
alert("jsRetryCancel");
break;
case (n & 4) == 4:
alert("jsYesNo");
break;
case (n & 3) == 3:
alert("jsYesNoCancel");
break;
case (n & 2) == 2:
alert("jsAbortRetryIgnore");
break;
case (n & 1) == 1:
alert("jsOKCancel");
break;
default:
alert("jsOKOnly");
}
switch(true)
{
case (n & 64) == 64:
alert("jsInformation");
break;
case (n & 48) == 48:
alert("jsExclamation");
break;
case (n & 32) == 32:
alert("jsQuestion");
break;
case (n & 16) == 16:
alert("jsCritical");
break;
}
switch(true)
{
case (n & 768) == 768:
alert("jsDefaultButton4");
break;
case (n & 512) == 512:
alert("jsDefaultButton3");
break;
case (n & 256) == 256:
alert("jsDefaultButton2");
break;
default:
alert("jsDefaultButton1");
}
switch(true)
{
case (n & 4096) == 4096:
alert("jsSystemModal");
break;
default:
alert("jsApplicationModal");
}
}


Am I wrong?

shmoove
12-01-2004, 09:41 AM
That is one way to go about it.
Another way would be to extract the exclusive flags. I'm not exactly familiar with these constants so I'll be going from the code you posted. It looks like the first set of exclusive options are 0-5, so they need the 3 lowest order bits. You can extract them using 7 (or 111 in binary):


buttonsFlag = n & 7;

For the second set, the options range between 16 and 64. So you want a number where all those bits are on. That would be 112 (or 1110000, or 16+32+64), so the second flag can be extracted like so:


typeFlag = n & 112;

The third set uses bits 9 and 10 (aka 256 and 512) so it can be extracted using 768 (1100000000):


defaultFlag = n & 768;

The last set uses one bit, the one for 4096, so we extract it with 4096:


modalFlag = n & 4096;

Then you can use simpler switch statements on these new flags, to get:


unpack(n) {
buttonsFlag = n & 7;
typeFlag = n & 112;
defaultFlag = n & 768;
modalFlag = n & 4096;

switch (buttonsFlag) {
case 0:
alert("jsOKOnly");
break;
case 1:
alert("jsOKCancel");
break;
case 2:
alert("jsAbortRetryIgnore");
break;
case 3:
alert("jsYesNoCancel");
break;
case 4:
alert("jsYesNo");
break;
case 5:
alert("jsRetryCancel");
break;
}
switch (typeFlag) {
case 16:
alert("jsCritical");
break;
case 32:
alert("jsQuestion");
break;
case 48:
alert("jsExclamation");
break;
case 64:
alert("jsInformation");
break;
}
// well, you get my drift.
}

If you really want to come to grips with this I suggest you grab a pencil and a piece of paper, and actually write down all the binary values, and play around with the various operations on them.

shmoove

codegoboom
12-01-2004, 10:37 AM
Aha... that makes more sense. Thanks! :cool:



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum