Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

CNumberFormat: A class for bit-field extraction out from 32 bit value values

0.00/5 (No votes)
11 Jan 2005 1  
An MFC class for fast extraction and interpretation of values from a 32 bit provided value.

Sample Image

Table of Contents

Purpose

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 bit15 and bit12 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.

Environment used

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:

...
#include "NumberFormat.h"

...

Now you are ready to use this class.

How to use this class

Construction

The CNumberFormat has a default constructor, but you also can build one by providing some attributes such as startBit, endBit and initial value. If these values are not provided, the new CNumberFormat item will have a startBit=0, endBit=31 and value=0.

    ...
    CNumberFormat format;
    // Build a CNumberFormat, with startBit=0, endBit=31, value=0.


    CNumberFormar *pFormat = new CNumberFormat(15,18);
    // startBit=15, endBit=18, value=0.

    ...

Copy-Construction is also possible from a reference or pointer (see below).

Duplication

Duplicating a CNumberFormat also is possible in different ways:

    ...
    //

    // Building a new format from an existing one

    //

    CNumberFormat newFormat(format);
    // Copy format to the new newFormat.


    CNumberFormar anotherFormat(pFormat);
    // Copy pFormat to the new anotherFormat.


    newFormat = anotherFormat; // copy via assignment operator..


    newFormat.Copy(pSourceNumberFormat);
     // Copy from a pointer to a CNumberFormat.


    newFormat.Copy(sourceNumberFormat);
    // Copy from a CNumberFormat item. (reference)

    ...

Just take care not to use a NULL pointer, otherwise you will get a default CNumberFormat item.

Attributes

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.

radix The format of the field, used to format strings. (ERadix enum type)

startBit

endBit

The range is built from the startBit and endBit.

The startBit is the offset to the less-significant-bit on the field.

The endBit is the offset to the most-significant-bit on the field.

The startBit should be less or equal to the endBit value.

Using these values, an internal mask is built for getting the relevant field from the stored/provided number.

noBits Number of bits the field contains. ((endBit-startBit)+1)
value 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 SetBitRange(), or SetStartBit(), or SetEndBit(), or during construction.

There is no getter for the value attribute. (I did not need such one!)

Field Extraction

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.)

Sample Image

The CNumberFormat that describes the phase-value can be defined and used as follows:

    ...
    CNumberFormat phaseValueFormat;
    unsigned long ul;
    signed long sl;
    unsigned long value;
    
    phaseValueFormat.SetBitRange(8,11);
    ...
    //

    // Read the 32bit unsigned register and store 

    // in the phaseValueFormat item

    //

    value = *HW_REGISTER;
    phaseValueFormat.SetValue(value);
    ...
    // Get the values stored on this field (signed and unsigned)

    ul = phaseValueFormat.GetUnsigned();
    sl = phaseValueFormat.GetSigned();
    ..
    // Another way to do it.

    ul = phaseValueFormat.GetUnsigned(value);
    // Just extract the field from value.


    sl = phaseValueFormat.GetSigned(*HW_REGISTER);
    // Translate on-the-fly.

    ...

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.

Formatting

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:)

    enum ERadix
    {
        UNSIGNED_RADIX = 0, ///< Display value as unsigned decimal.
        SIGNED_RADIX,       ///< Display value as signed decimal.
        HEXADECIMAL_RADIX,  ///< Display value as unsigned hexadecimal (0x...)
        NO_RADIX            ///< Don't display value.
    };

For generating a CString containing the formatted number, do as follows:

    ...
    // Produce an hexadecimal string when required.

    phaseValueFormat.SetRadix(CNumberFormat::HEXADECIMAL_RADIX);
    
    CString phaseValueText1 = phaseValueFormat.GetString();
    // Get the value stored..


    CString phaseValueText2 = phaseValueFormat.GetString(*HW_REGISTER);
    // Translate on-the-fly...

    ...

If you need a string describing the field range, you can use the GetRangeString() method.

That is all Folks!

Code Documentation

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.

Provided Files

Source files:

  • NumberFormat.h and
  • NumberFormat.cpp

Some words about the demo application provided

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).
Range: The endBit and startBit that describes the extracted value. The formatted string is as follows: "[endBit:startBit]".
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.

Disclaimer

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!.

Terms of use

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.

ChangeLog

Date Rev. Description
2005/Jan/09 1.0 Debut in CodeProject.
2002/May/11 --- Created.

Epilogue

Hope that this simple class is useful for you.

To help other users in CodeProject, please Rate this Article :)

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here