c - 在c中用struct提取位域

标签 c struct bit-manipulation intel cpu-registers

我使用这两种方法从寄存器中获取位域信息。我需要提取的位字段的位置由英特尔手册给出。正如下面的代码。但是我得到的结果与这两种方法不同。

我找不到这两种方法的任何问题。但据我了解,maximum_power filed 不应该像第一种方法那样为'0'(这是英特尔已经在寄存器中定义的值。)

方法一:

typedef struct rapl_parameters_msr_t {
  uint64_t thermal_spec_power        : 15;
  uint64_t                           : 1;
  uint64_t minimum_power             : 15;
  uint64_t                           : 1;
  uint64_t maximum_power             : 15;
  uint64_t                           : 1;
  uint64_t maximum_limit_time_window : 6;
  uint64_t                           : 10;
} rapl_parameters_msr_t;

uint64_t              msr;
read_msr(cpu, 0x614, &msr);

rapl_parameters_msr_t domain_msr = *(rapl_parameters_msr_t *)&msr;
printf("%ld\n", domain_msr.thermal_spec_power);  //print: 280
printf("%ld\n", domain_msr.minimum_power);  //print: 192
printf("%ld\n", domain_msr.maximum_power);  //print: 0
printf("%ld\n", domain_msr.maximum_limit_time_window);  //print: 16

方法二:

uint64_t 
extractBitField(uint64_t inField, uint64_t width, uint64_t offset)
{
    uint64_t bitMask;
    uint64_t outField;

    if ((offset+width) == 32) 
    {
        bitMask = (0xFFFFFFFF<<offset);
    }
    else 
    {  /*Just keep the filed needs to be extrated*/
        bitMask = (0xFFFFFFFF<<offset) ^ (0xFFFFFFFF<<(offset+width));  

    }
    /*Move to the right most field to be calculated*/
    outField = (inField & bitMask) >> offset;
    return outField;
}
uint64_t              flags;
read_msr(cpu, 0x614, &flags);
printf("thermal power: %d\n", extractBitField(flags,15,0));  //print: 280
printf("minimum power: %d\n", extractBitField(flags,15,16));//print: 192
printf("maximum power: %d\n", extractBitField(flags,15,32));//print: 0
printf("time window: %d\n", extractBitField(flags,6,48));  //print: 0

您是否知道问题出在哪里?

更新:

抱歉让您感到困惑。我将所有类型更改为 uint64_t,方法 2 的最大功率和时间窗口均为 0。

如果编译器可能对方法 1 产生错误的结果,我仍然怀疑我对方法 2 结果的信任度有多大。

以下是英特尔手册中的位表示文档:

Thermal Spec Power (bits 14:0)
Minimum Power (bits 30:16)
Maximum Power (bits 46:32)
Maximum Time Window (bits 53:48)

感谢 David,这是 64 位提取的正确版本。

uint64_t 
extractBitField(uint64_t inField, uint64_t width, uint64_t offset)
{
    uint64_t bitMask;
    uint64_t outField;

    if ((offset+width) == 64) 
    {
        bitMask = (0xFFFFFFFFFFFFFFFF<<offset);
    }
    else 
    {  /*Just keep the filed needs to be extrated*/
        bitMask = (0xFFFFFFFFFFFFFFFF<<offset) ^ (0xFFFFFFFFFFFFFFFF<<(offset+width));  

    }
    /*Move to the right most field to be calculated*/
    outField = (inField & bitMask) >> offset;
    return outField;
}
uint64_t              flags;
read_msr(cpu, 0x614, &flags);
printf("thermal power: %d\n", extractBitField(flags,15,0));  //print: 280
printf("minimum power: %d\n", extractBitField(flags,15,16));//print: 192
printf("maximum power: %d\n", extractBitField(flags,15,32));//print: 0
printf("time window: %d\n", extractBitField(flags,6,48));  //print: 16

最佳答案

C 位域中位的顺序是实现定义的,所以如果您计划使用它们,请小心——您认为获得的顺序可能与您实际的顺序不同。查看编译器的文档以了解它如何处理此问题。

此外,您的第二个函数采用 uint32,而您的第一个示例使用的是 64 位结构,因此您的类型不匹配。你能更正它并更新你的结果吗?

编辑:此外,您在第一个示例中将时间窗定义为 6 位,在第二个示例中定义为 15 位。

C99:6.7.2.1p10 An implementation may allocate any addressable storage unit large enough to hold a bit- field. If enough space remains, a bit-field that immediately follows another bit-field in a structure shall be packed into adjacent bits of the same unit. If insufficient space remains, whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is implementation-defined. The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined. The alignment of the addressable storage unit is unspecified.

关于c - 在c中用struct提取位域,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24089751/

相关文章:

c - Stack中的局部变量及其在C程序中的使用顺序

c - 将指针移交给 C 中的另一个函数

c++ - 指向 POD 结构的 C/C++ 指针也指向第一个结构成员

java - 使用 JNI 或其他工具,是否可以在 Java 中实现 C 代码的反射?

c++ - 第一个索引后未填充结构数组索引

bit-manipulation - 如何使用 AND、XOR 和 shift 计算按位或?

android - 免费的条形码图像解码库

c - 为什么 `printf("%s", "foo")` not being optimized to ` fputs ("foo", stdout)`?

java - 大输入数组中的奇数异或对

c++ - 将整数紧密地打包在一个 vector 中 - 可以更快地完成吗?