Table of Contents
The motivation in writing this
CNumberFormat class was:
- Fast parsing of data retrieved from some hardware registers and interpret the values stored as separated fields. (E.g., look only on the field located between bit
15 and bit
12 as a signed 4 bit width value.)
- Capable to interpret the values as signed or unsigned values according to the needs.
- Provide formatted strings in case the values are displayed on some kind of user interface.
The following considerations were taken:
- Numbers are stored as Little-Endian numbers. If you plan to use this class for Big-Endian byte ordering, you should tailor it for your needs. Currently there is no check about the Endianness used. (See Basic concepts on Endianness[^] in this site if you need help with Endianness...)
- Numbers are limited up to 32 bits. If you plan to use this class for 64 bits, some changes are also required.
I used this class to parse hundreds of fields stored in registers retrieved from some hardware to produce some statistics and graphs. The whole register-map was read periodically at a rate of 10 msec.
This class was initially developed using VC 6.0 (Visual Studio C++ 6.0), and now I'm using VC 7.1 (Visual Studio C++ .NET 2003). The demo application will compile only on VC 7.1 due that I'm using some MFC stuff not present in VC 6.0. The class
CNumberFormat will compile also in VC 6.0..
Adding the CNumberFormat class to your project
Make sure you have got two files: NumberFormat.h and NumberFormat.cpp, copy them to your project directory.
Open your project in your developing environment and add these files to your project.
To the relevant files, add the following line in your includes section:
Now you are ready to use this class.
CNumberFormat has a default constructor, but you also can build one by providing some attributes such as
endBit and initial value. If these values are not provided, the new
CNumberFormat item will have a
CNumberFormar *pFormat = new CNumberFormat(15,18);
Copy-Construction is also possible from a reference or pointer (see below).
CNumberFormat also is possible in different ways:
newFormat = anotherFormat;
Just take care not to use a
NULL pointer, otherwise you will get a default
Any time, the different attributes can be set using any of the provided setter functions.
The following table lists the different attributes stored on a
CNumberFormat. For clarity, the names here are not the same as the private members used on the class.
|The format of the field, used to format strings. (|
The range is built from the
startBit is the offset to the less-significant-bit on the field.
endBit is the offset to the most-significant-bit on the field.
startBit should be less or equal to the
Using these values, an internal mask is built for getting the relevant field from the stored/provided number.
|Number of bits the field contains. (|
|The 32 bit unsigned value provided. From this value, the field is extracted.|
There is no setter for the
noBits attribute. This attribute is set using the
SetEndBit(), or during construction.
There is no getter for the
value attribute. (I did not need such one!)
Let's assume we read a register containing a 'phase-value' field that is stored on bits
11 down to
8. (A 4 bit field.)
CNumberFormat that describes the phase-value can be defined and used as follows:
unsigned long ul;
signed long sl;
unsigned long value;
value = *HW_REGISTER;
ul = phaseValueFormat.GetUnsigned();
sl = phaseValueFormat.GetSigned();
ul = phaseValueFormat.GetUnsigned(value);
sl = phaseValueFormat.GetSigned(*HW_REGISTER);
From the experience I have with this class, most of the time you will be doing 'on-the-fly' translations, as shown in the last line on the code above.
If you need to provide a string containing the field value, you need also to set the
radix of the value you want to display. The following
enum is defined on this class for this purpose. (You may use the enumerated constants or just an integer for setting the radix for the format of the field to be extracted. From the NumberFormat.h header file:)
UNSIGNED_RADIX = 0,
For generating a
CString containing the formatted number, do as follows:
CString phaseValueText1 = phaseValueFormat.GetString();
CString phaseValueText2 = phaseValueFormat.GetString(*HW_REGISTER);
If you need a string describing the field range, you can use the
That is all Folks!
The code contains DOxygen comments, used to generate HTML documentation out of the code. I strongly advice you to use such a tool, directly or indirectly.
DOxygen is a documentation system for C++, C, Java, Objective-C, IDL (CORBA and Microsoft flavors) and to some extent PHP, C# and D. It can be found in www.doxygen.org[^].
The companion help file was generated using the KingsTools[^] Visual Studio .NET Add-In by SteveKing[^], This add-in contains several useful tools you may like to have integrated in your developing environment. (DOxygen, code-statistics, syntax coloring, etc.).
Thanks to SteveKing for this tool, and his disclaimer note I'm using in my code.
- NumberFormat.h and
Although the demo application is overkill for showing the usage of this class, I hope that this demo may help others also on how to use timers, virtual-list controls, etc. If you want to focus only on the
CNumberFormat class, take a look on the addition of new ranges using the
CArray template and in the method
CDemoDlg::OnListLvnGetdispinfo() on the provided demo source-code.
The demo application will shuffle a 32 bit value out of the
::GetTickCount() system call every ~2sec to give the user the time to look on the results. The shuffled value is displayed on a read-only edit box (hexadecimal and binary formats).
The table shows the same value parsed according to the bit-range and radix selected. The columns of the table are:
|Bits:||Number of bits on the extracted value (from 1 up to 32).|
startBit that describes the extracted value. The formatted string is as follows: "
|Unsigned:||The unsigned decimal representation of the extracted field.|
|Signed:||The signed or twos-complement representation of the extracted field.|
|Hexa:||The unsigned hexadecimal representation of the extracted field.|
Two buttons are also provided, one for adding a new range to the end of the list (you may add any number or new range descriptions), and a delete-all button for removing the contents of the list.
All the numbers on the table are extracted from the same victim value as displayed on the read-only edit box.
This code and the accompanying files are provided "as is" with no expressed or implied warranty. No responsibilities for possible damages, or side effects in its functionality. The user must assume the entire risk of using this code. The author accepts no liability if it causes any damage to your computer, causes your pet to fall ill, increases baldness or makes your car start emitting strange noises when you start it up. This code has no bugs, just undocumented features!.
This code is free for personal use, or freeware applications. If you plan to use this code in a commercial or shareware application, you are politely asked to contact the author for his permission.
|2005/Jan/09||1.0||Debut in CodeProject.|
Hope that this simple class is useful for you.
To help other users in CodeProject, please Rate this Article :)