Bitwise Operations

Started by
26 comments, last by torakka 17 years, 7 months ago
I'd never use #defines in the manner in which I posted. that was just copied straight out of an MFC class...oops did i just admit that. Slap my wrist for not posting good style....as well as the bitwise operator bug....I'll get my coat.
Advertisement
Quote:Original post by Serapth
Why dont you ever see something like:
#pragma pack(1)struct _PackedChar {	const unsigned char bitOne :1;	const unsigned char bitTwo :1;	const unsigned char bitThree :1;	const unsigned char bitFour :1;	const unsigned char bitFive :1;	const unsigned char bitSix :1;	const unsigned char bitSeven :1;	const unsigned char bitEight :1;};#pragma pack() 

One reason is that the order of the members may vary between compilers and platforms. Thus it is not portable in many circumstances (such as data loaded from a file). Another is that it is more convenient to waste a few bytes and just use bools.
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
Quote:Original post by JohnBolton
Quote:Original post by Serapth
Why dont you ever see something like:
#pragma pack(1)struct _PackedChar {	const unsigned char bitOne :1;	const unsigned char bitTwo :1;	const unsigned char bitThree :1;	const unsigned char bitFour :1;	const unsigned char bitFive :1;	const unsigned char bitSix :1;	const unsigned char bitSeven :1;	const unsigned char bitEight :1;};#pragma pack() 

One reason is that the order of the members may vary between compilers and platforms. Thus it is not portable in many circumstances (such as data loaded from a file). Another is that it is more convenient to waste a few bytes and just use bools.


Order wouldnt matter though, would it? I mean, even if you run it on a machine with different endian-ness _PackedChar.bitOne would resolve to the same value. Infact, wouldnt that solve endian issues? I mean, if your code used say WM_PAINT with a value of say 0x0001, unless you have a conditional define for reversed endian processors, the value you mask WM_PAINT against will fail?

If anything, I would think a packed bit struct would be more portable then a #define... not that I like either.
He's talking about the situation where you write out a PackedChar to a file, and then read it back in as a char, on a different platform - or even the same platform, with the code compiled by a different compiler, or different compiler settings.
I have seen it used in older game programming books(lamothe game programming books) in regard to mouse and joystick input using the win32api.
The new and easier way is to use directx.
See for yourself how it was used to detect mouse and joystick input here
And as you can see here is some of my code for a win32api game engine and it's pretty ugly:
[source language=cpp]BOOL GameEngine::InitJoystick(){  // Make sure joystick driver is present  UINT uiNumJoysticks;  if ((uiNumJoysticks = joyGetNumDevs()) == 0)    return FALSE;  // Make sure the joystick is attached  JOYINFO jiInfo;  if (joyGetPos(JOYSTICKID1, &jiInfo) != JOYERR_UNPLUGGED)    m_uiJoystickID = JOYSTICKID1;  else    return FALSE;  // Calculate the trip values  JOYCAPS jcCaps;  joyGetDevCaps(m_uiJoystickID, &jcCaps, sizeof(JOYCAPS));  DWORD dwXCenter = ((DWORD)jcCaps.wXmin + jcCaps.wXmax) / 2;  DWORD dwYCenter = ((DWORD)jcCaps.wYmin + jcCaps.wYmax) / 2;  m_rcJoystickTrip.left = (jcCaps.wXmin + (WORD)dwXCenter) / 2;  m_rcJoystickTrip.right = (jcCaps.wXmax + (WORD)dwXCenter) / 2;  m_rcJoystickTrip.top = (jcCaps.wYmin + (WORD)dwYCenter) / 2;  m_rcJoystickTrip.bottom = (jcCaps.wYmax + (WORD)dwYCenter) / 2;  return TRUE;}void GameEngine::CaptureJoystick(){  // Capture the joystick  if (m_uiJoystickID == JOYSTICKID1)    joySetCapture(m_hWindow, m_uiJoystickID, NULL, TRUE);}void GameEngine::ReleaseJoystick(){  // Release the joystick  if (m_uiJoystickID == JOYSTICKID1)    joyReleaseCapture(m_uiJoystickID);}void GameEngine::CheckJoystick(){  if (m_uiJoystickID == JOYSTICKID1)  {    JOYINFO jiInfo;    JOYSTATE jsJoystickState = 0;    if (joyGetPos(m_uiJoystickID, &jiInfo) == JOYERR_NOERROR)    {      // Check horizontal movement      if (jiInfo.wXpos < (WORD)m_rcJoystickTrip.left)        jsJoystickState |= JOY_LEFT;      else if (jiInfo.wXpos > (WORD)m_rcJoystickTrip.right)        jsJoystickState |= JOY_RIGHT;      // Check vertical movement      if (jiInfo.wYpos < (WORD)m_rcJoystickTrip.top)        jsJoystickState |= JOY_UP;      else if (jiInfo.wYpos > (WORD)m_rcJoystickTrip.bottom)        jsJoystickState |= JOY_DOWN;      // Check buttons      if(jiInfo.wButtons & JOY_BUTTON1)        jsJoystickState |= JOY_FIRE1;      if(jiInfo.wButtons & JOY_BUTTON2)        jsJoystickState |= JOY_FIRE2;    }    // Allow the game to handle the joystick    HandleJoystick(jsJoystickState);  }

where
typedef WORD JOYSTATE;
const JOYSTATE JOY_NONE = 0x0000L,
JOY_LEFT = 0x0001L,
JOY_RIGHT = 0x0002L,
JOY_UP = 0x0004L,
JOY_DOWN = 0x0008L,
JOY_FIRE1 = 0x0010L,
JOY_FIRE2 = 0x0020L;
[size="2"]Don't talk about writing games, don't write design docs, don't spend your time on web boards. Sit in your house write 20 games when you complete them you will either want to do it the rest of your life or not * Andre Lamothe
I have another question about bitwise operations. How do you know what bitwise operator to use in your program? Do you just experient with combining two binary numbers until you get the result you want or is there a method to the madness? I know shifting multiplies and divides, but what does & and | do other then compare bits of two differnt numbers?
You use | to set them and & to check them. Using my example above:

status = DEAD; // => 0000 0010

// Set it
status = status | ALIVE; // easier is status |= ALIVE;

This will do
0000 0010  OR0000 0001-----------0000 0011 = 3 => New value for status ( note how it didn't affect the DEAD bit )


If you want to check to see if the DEAD flag is set you do:
if ( status & DEAD )...
This will do:

0000 0011 AND0000 0010--------------0000 0010 => Non zero = true



if the flag is not set, say UNDEAD
if ( status & UNDEAD )
0000 0011 AND0000 0100----------0000 0000 =>  0 = false (flag not set)
AND(&) asks are the bits in value1 and value2 both 1, then it remains 1, otherwise it is set to 0.

For example 0101 & 0100 would become 0100

OR(|) asks if either bit is 1, if either is 1 ( or both bits ), the result is 1.

For example 1100 | 0101 would become 1101
With | your person is both dead and alive? lol Sets flags to both dead and alive?

With & your person is dead. Checks to see if the flag for dead is set?
Quote:Original post by Chris27
I have another question about bitwise operations. How do you know what bitwise operator to use in your program? Do you just experient with combining two binary numbers until you get the result you want or is there a method to the madness? I know shifting multiplies and divides, but what does & and | do other then compare bits of two differnt numbers?


The operators are named after their boolean algebra equivalents. Your probably want to learn how binary and hexadecimal works as well if you really want to understand what is going on.

&(and) = any bit multipled by a 0 becomes 0.

  101010& 110110--------  100010


Say you had a byte and wanted to get what just the last two bits equaled:

unsigned char SomeByte = 0x9A;
unsigned char Upper2Bits = SomeByte & 0x60;

This is equal to:

  10011010(SomeByte)& 11000000(0x60)----------  10000000(Upper2Bits);



|(or) = any bit plus 1 becomes 1.

  101010| 110110--------  111110


Using daviangel's example lets say we have a 16-bit integer with data from the joystick. Now if you want to know if the FIRE1 button was press:

  10111000(Joystick data)& 00010000(JOY_FIRE1, 0x0010)----------  00010000(Above 0 = true);


Now if you wanted to set the JOY_FIRE1 bit:

  10101000(Joystick data)| 00010000(JOY_FIRE1, 0x0010)----------  10111000(Joystick data now has JOY_FIRE1 set);


If you still don't understand it, do searches for binary, boolean algebra and hexadecimal(preferably in that order).

Edit: Way too slow :(

This topic is closed to new replies.

Advertisement