65.9K
CodeProject 正在变化。 阅读更多。
Home

CNumberFormat:一个用于从32位值中提取位域的类

2005年1月12日

7分钟阅读

viewsIcon

45298

downloadIcon

1297

一个MFC类,用于从提供的32位值中快速提取和解释值。

Sample Image

目录

目的

编写此CNumberFormat类的动机是

  • 快速解析从某些硬件寄存器检索到的数据,并解释存储为分隔字段的值。(例如,只查看位于位15和位12之间的字段,作为一个有符号的4位宽度值。)
  • 能够根据需要将值解释为有符号或无符号值。
  • 如果值显示在某种用户界面上,则提供格式化的字符串。

考虑了以下几点

  • 数字存储为小端数字。如果您计划使用此类处理大端字节序,则需要根据您的需求进行定制。目前没有检查使用的字节序。(如果您需要关于字节序的帮助,请参阅本站的字节序基本概念[^]...)
  • 数字限制在32位以内。如果您计划使用此类处理64位,也需要进行一些更改。

我使用此类解析了从硬件检索到的寄存器中存储的数百个字段,以生成一些统计信息和图表。整个寄存器映射以10毫秒的速率定期读取。

使用的环境

此类最初是使用VC 6.0 (Visual Studio C++ 6.0) 开发的,现在我正在使用VC 7.1 (Visual Studio C++ .NET 2003)。演示应用程序只能在VC 7.1上编译,因为我使用了一些VC 6.0中不存在的MFC功能。CNumberFormat也可以在VC 6.0中编译

将CNumberFormat类添加到您的项目中

确保您有两个文件:NumberFormat.hNumberFormat.cpp,将它们复制到您的项目目录。

在您的开发环境中打开您的项目,并将这些文件添加到您的项目中。

在相关文件中,在您的includes部分添加以下行

...
#include "NumberFormat.h"
...

现在您可以使用此类了。

如何使用此类

然后,当你开始迭代 2(这是构建迭代的开始)时,你可能想要复制测试用例并将它们重新分类到迭代 2。这还允许对测试用例进行粒度跟踪,并允许你说某个测试用例在一个迭代中是准备好的,但在另一个迭代中不是。同样,如何做到这一点取决于你以及你希望如何报告。 “场景”部分提供了更多细节。

CNumberFormat有一个默认构造函数,但您也可以通过提供一些属性来构建一个,例如startBitendBit和初始值。如果未提供这些值,则新的CNumberFormat项将具有startBit=0endBit=31value=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.
    ...

也可以通过引用或指针进行复制构造 (见下文)。

复制

复制CNumberFormat也可以有多种方式

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

请注意不要使用NULL指针,否则您将获得一个默认的CNumberFormat项。

属性

任何时候,都可以使用提供的任何setter函数来设置不同的属性。

下表列出了CNumberFormat中存储的各种属性。为清楚起见,这里的名称与类中使用的私有成员名称不同。

基数 字段的格式,用于格式化字符串。(ERadix enum 类型)

起始位

结束位

范围由startBitendBit构成。

startBit是字段中最低有效位的偏移量。

endBit是字段中最高有效位的偏移量。

startBit应小于或等于endBit值。

使用这些值,将构建一个内部掩码,用于从存储/提供的数字中获取相关字段。

位数 字段包含的位数。((endBit-startBit)+1)
value 提供的32位无符号值。从中提取字段。

noBits属性没有setter。此属性使用SetBitRange()SetStartBit()SetEndBit()设置,或在构造时设置。

value属性没有getter。(我不需要这个!)

字段提取

假设我们读取一个包含“phase-value”字段的寄存器,该字段存储在从位118。(一个4位字段。)

Sample Image

描述phase-valueCNumberFormat可以定义和使用如下:

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

根据我对此类的经验,大多数时候您将进行“即时”转换,如上面代码的最后一行所示。

格式化

如果您需要提供一个包含字段值的字符串,您还需要设置要显示的radix。类中为此目的定义了以下enum。(您可以使用枚举常量或仅使用整数来设置要提取的字段格式的基数。来自NumberFormat.h头文件:)

    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.
    };

要生成包含格式化数字的CString,请执行以下操作:

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

如果您需要一个描述字段范围的字符串,可以使用GetRangeString()方法。

就这样,大家!

代码文档

代码包含DOxygen注释,用于从代码生成HTML文档。我强烈建议您直接或间接使用此类工具。

DOxygen是一个用于C++、C、Java、Objective-C、IDL (CORBA和Microsoft风格) 以及在一定程度上PHP、C#和D的文档系统。可以在www.doxygen.org[^]找到。

配套的帮助文件是使用KingsTools[^] Visual Studio .NET加载项由SteveKing[^]生成的,这个加载项包含几个您可能喜欢集成到开发环境中的有用工具。(DOxygen、代码统计、语法着色等)。

感谢SteveKing提供的这个工具,以及他用于我代码的免责声明

提供的文件

源文件

  • NumberFormat.h
  • NumberFormat.cpp

关于提供的演示应用程序的一些说明

尽管演示应用程序对于展示此类用法来说是杀鸡焉用牛刀,但我希望这个演示也能帮助其他人了解如何使用定时器、虚拟列表控件等。如果您只想关注CNumberFormat类,请查看如何使用CArray模板添加新范围,以及在提供的演示源代码的CDemoDlg::OnListLvnGetdispinfo()方法中。

演示应用程序将每隔约2秒钟从::GetTickCount()系统调用中随机抽取一个32位值,让用户有时间查看结果。随机抽取的值显示在一个只读编辑框中 (十六进制和二进制格式)。

下表显示了根据选定的位范围和基数解析的相同值。表中的列是:

提取值中的位数 (从1到32)。
Range 描述提取值的endBitstartBit。格式化字符串如下:“[endBit:startBit]”。
无符号 提取字段的无符号十进制表示。
有符号 提取字段的有符号或补码表示。
十六进制 提取字段的无符号十六进制表示。

还提供了两个按钮,一个用于在列表末尾添加一个新范围 (您可以添加任何数量的新范围描述),另一个是删除所有按钮,用于删除列表中的内容。

表中的所有数字都是从只读编辑框中显示的同一个受害者值中提取出来的。

免责声明

此代码及附带文件按“原样”提供,不附带任何明示或暗示的保证。对其功能可能造成的损害或副作用不承担任何责任。用户必须承担使用此代码的全部风险。如果此代码导致您的计算机损坏、您的宠物生病、您变秃头或您的汽车启动时发出奇怪的噪音,作者概不负责。此代码没有错误,只有未记录的功能!

使用条款

此代码免费供个人使用或免费应用程序使用。如果您计划在商业或共享软件应用程序中使用此代码,我们礼貌地请求您联系作者以获得许可。

变更日志

日期 版本 描述
2005/01/09 1.0 在CodeProject首次发布。
2002/05/11 --- 创建。

结语

希望这个简单的类对您有用。

为了帮助CodeProject上的其他用户,请评价此文章:)

© . All rights reserved.