These days there are fewer and fewer reasons to pack multiple numbers into a single integer using bit packing. But you still come across it occasionally.

A while ago I had to debug some code that was handling such where a time period was packed into 32 bit integer, with the top 12 bits the year, the next 4 the month and the bottom 16 the day.

class TimePeriod
{
private:
	unsigned int value_;

public:
	TimePeriod(int days, int months, int years)
	{
		value_ = days;
		value_ += months << 16;
		value_ += years << 20;
	}

	int days() const { return (value_ & 0xFFFF); }
	int months() const { return (value_ & 0xF0000) >> 16; }
	int years() const { return value_ >> 20; }
};

It is deeply ingrained class that was written 15 odd years ago and wasn’t going to be changed in version of the code I was looking at.

Of course it is not very obvious when in the debugger as to what this class is doing.

Thankfully the Visual Studio debugger can be customized for displaying different types. Because this is a fairly simple type this can be done by inserting an entry into the visualizers file that you’ll find at C:\Program Files\Microsoft Visual Studio 9.0\Common7\Packages\Debugger\autoexp.dat (or similar).

TimePeriod{
    preview (
        #(
            (($c.value_ & 0xFFF00000) >> 20), " years ",
            (($c.value_ & 0xF0000) >> 16), " months ",
            ($c.value_ & 0xFFFF), " days"
        )    
    )
    children
    (
        #(
            [raw] : [$c,!],
            years : (($c.value_ & 0xFFF00000) >> 20),
            months : (($c.value_ & 0xF0000) >> 16),
            days : ($c.value_ & 0xFFFF)
        )
    )
}

Other things that are useful to put in your AutoExp.dat file

All of these go in the visualizers section, I can’t take credit for these but unfortunately I can’t remember where I found them.

;------------------------------------------------------------------------------
;  CArray
;------------------------------------------------------------------------------
CArray<*>|CDWordArray|CWordArray|CByteArray|CUIntArray|CPtrArray|CObArray|CStringArray{
   preview
   (
      #( "[", [$c.m_nSize], "](",
          #array
          (
             expr : $c.m_pData[$i],
             size : $c.m_nSize
         ),
      ")")
   )

   children
   (
      #(
         [raw] : [$e,!],
         #array
         (
             expr : $c.m_pData[$i],
             size : $c.m_nSize
         )
      )
   )
}

;------------------------------------------------------------------------------
;  CMap
;------------------------------------------------------------------------------
CMap<*>|CMapPtrToPtr|CMapPtrToWord|CMapWordToPtr|CMapWordToOb|CMapStringToPtr|CMapStringToOb|CMapStringToString{
   preview
   (
         #( "[", [$c.m_nCount], "](",
         #array
         (
             expr : $c.m_pHashTable[$i],
             size : $c.m_nHashTableSize
         ) : #list (
                 head : &$e,
                 next : pNext
             ) : $e,
      ")")
   )

   children
   (
      #(
         #array
          (
             expr : $e.m_pHashTable[$i],
             size : $e.m_nHashTableSize
         ) : #list (
                 head : &$e,
                 next : pNext
             ) : $e
      )
   )
}

CMap<*>::CAssoc|CMapPtrToPtr::CAssoc|CMapPtrToWord::CAssoc|CMapWordToPtr::CAssoc|CMapWordToOb::CAssoc|CMapStringToPtr::CAssoc|CMapStringToOb::CAssoc|CMapStringToString::CAssoc {
   preview
   (
      #(
          "(",
          $e.key,
          ",",
          $e.value,
          ")"

      )
   )

   children
   (
     #(
         key: $c.key,
         value: $c.value
      )
   )
}

For more complicated types it is possible to write extension dlls that the debugger can use for visualization.