Friday, November 09, 2007

Privateering

Nothing divides programmers more than coding style, in particular the representation of private member variables.

Here are some of the options;



class Class
{
    m_member
    m_Member

    _member
    _Member

    member
    Member
};




The problem is, if you are like me you don't particularly like prefixes like m_ or _ and the problem with not using a prefix is that it can conflict with method names.

Using prefixes unfortunately can create bad code since it encourages programmers not to think about naming or the number of members in a class.

The solution can be to use a lower case member name and an upper case method name, but then there is no distinction between local variables and member variables within a method body.

Another less common solution which i use sometimes, since i always prefer to use no prefixes and uppercase member names just like methods, is to wrap my private members in a struct to remove the naiming conflict but keep the cleanliness and readability.



class Class
{

struct PrivateMembers
{
Member;
}

PrivateMembers Private;

void Member()
{
Private.Member;
}
};

Shifting

Dos Date Time
Two's Compliment

I recently encountered this strange but simple bug in some code that i had written to convert from posix standard to dos standard time. It was strange becuase it only shows up when you use dates and times which are earlier than a certain magic number.

Dos uses a strange bit packed representation of date and time in two 16 bit words. Within each word the various values occupy a set number of bits as follows.


Date Format

0-4 Day of the month (1–31)
5-8 Month (1 = January, 2 = February, and so on)
9-15 Year offset from 1980 (add 1980 to get actual year)

Time Format
0-4 Second divided by 2
5-10 Minute (0–59)
11-15 Hour (0–23 on a 24-hour clock)


So assuming you have some simple integer representation of time and date, lets call it a Calendar you might use the following code to convert to and from the Dos format.



// Conversion to dos date and time
Calendar calendar;
short date = ((calendar.Year - 1980)<<9)
+ ((calendar.Month)<<5) + calendar.Day;
short time = ((calendar.Hour)<<11)
+ ((calendar.Minute)<<5) + (calendar.Second/2);

// Conversion from dos date and time
Calendar calendar;
calendar.Year = ((date>>9)&0x007F)+1980; // 7 bits
calendar.Month = ((date>>5)&0x000F); // 4 bits
calendar.Day = (date&0x001F); // 5 bits

calendar.Hour = ((time>>11)&0x001F); // 5 bits
calendar.Minute = ((time>>5)&0x003F); // 6 bits
calendar.Second = (time&0x001F)*2; // 5 bits




So wheres the bug ?

Well, the bug occurs when you use a year earlier than 1980, for example 1970. What happens is that thanks to the subtraction of 1980 from the year you end up with a negative number which is left shifted 9 bits into the 16 bit word.

Now usually when you do bit packing, its standard practice to mask the bits as you extract them by using an binary and after the right shift operation. This ensures that the value you get is isolated from the other bits, especially those further to the left since usually you right shift until zero.

In this case though the year is different from the other values in the date word. Becuase the year occupies the left most bits, its two's compliment representation as a negative number is preserved all the way through the right shift operation until the binary and, where it is suddenly forced into being a positive integer with the same 7 bits, changing it from a small negative to a large positive number.

The solution is to remove the binary and mask on the year. For all other values the mask is still necessary, but due to the weird although perhaps purposeful design of the dos date and time format, the year is special.