【问题标题】:How to pass a bitfield (by reference) to a function?如何将位域(通过引用)传递给函数?
【发布时间】:2011-04-15 10:20:01
【问题描述】:

我的问题是如何通过引用函数来传递位域实例。我已经按如下所示执行了此操作,但是当我输入函数 DAC_set_gain_code 时,处理器会引发中断故障。就通过位域而言,我所做的是否正确?

我已经创建了一个位域(见下文),它表示 DAC 芯片上的一个 24 位寄存器,我想将其写入并保存在 .h 文件中。

typedef struct {
    uint8_t rdwr_u8:        1;
    uint8_t not_used_u8:    3;
    uint8_t address_u8:     4;
    uint8_t reserved_u8:    8;
    uint8_t data_u8:        8;
}GAIN_REG_st;

我有一个像这样初始化位域的函数:

void init(void)
{
    GAIN_REG_st GAIN_x;  //Create instance of bitfield

    //other code here...

    DAC_set_gain_code(channel_u8, gain_code_i8, &GAIN_x);   //Pass address of bitfield

    return;
 }

实际填充位域的函数如下所示:

void DAC_set_gain_code(uint8_t channel_u8, int8_t gain_code_i8, GAIN_REG_st *GAIN)
{
    /* Populate ZERO_REG_st bitfield */
    GAIN->rdwr_u8       = 0;
    GAIN->not_used_u8 = 0;

    if(channel_u8==0){
        GAIN->address_u8 = GAIN_REGISTER_0;
    }
    else if(channel_u8==1){
        GAIN->address_u8 = GAIN_REGISTER_1;
    }
    else if(channel_u8==2){
        GAIN->address_u8 = GAIN_REGISTER_2;
    }
    else if(channel_u8==3){
        GAIN->address_u8 = GAIN_REGISTER_3;
    }

    GAIN->data_u8 = gain_code_i8;

    return;
}

hal_DAC_set_gain_code_uni 的函数原型是:

void DAC_set_gain_code(uint8_t channel_u8, int8_t gain_code_i8, GAIN_REG_st *GAIN);

任何建议表示赞赏。

谢谢。

【问题讨论】:

  • 您发布的内容可能无法编译,或者您没有显示您实际使用的内容(函数名称不匹配、未声明的变量和/或未显示的全局变量以及未使用的参数)
  • 还是不行。 ZERO 未在您发布的内容中定义,GAIN 未在 DAC_set_gain_code 中使用。
  • 对帖子中的错误表示抱歉。现在应该与实际代码相同。我的主要问题是,我是否正确传递了位域的引用?
  • 我的代码编译没有错误,所以未声明的变量和函数名不匹配不是问题。
  • 嗯,是的,你正确地传递了一个指针(C 中没有引用本身)。但是您发布的代码仍然不是您所拥有的(GAIN 没有名为 data_u16 的成员。您确定您的程序在该函数中死亡,而不是在它之后不久?

标签: c embedded device-driver microcontroller bit-fields


【解决方案1】:

由于此代码的真正用途是写入硬件寄存器,因此字段确实的填充和对齐/排序等问题很重要。

我怀疑编译器使用的是 32 位整数,并且这个结构被填充到 32 位,但在实际调试的代码中,GAIN_X 不是本地变量,您传递的是 0xNNNNNNN(或等效值)-并且地址不在“正确”边界上(很可能,因为它是一个 24 位寄存器)。编译器将假定您传递的是指向真正 GAIN_REG_st 的指针,而不是类型双关地址,因此可能对对齐做出了假设。

要直接从 C/C++ 访问硬件,您需要知道编译器如何处理此类事情,并确保您小心地对编译器撒谎。

【讨论】:

    【解决方案2】:

    会不会是对齐问题?

    也许您可以使用编译器的对齐选项? 或者尝试在最后用一个虚拟的uint8 填充你的结构?

    【讨论】:

    • 但是没有演员表,所以不可能是对齐问题
    • 是的,可能存在对齐问题。当涉及位域时,C 允许编译器完全混乱并以完全任意的方式对齐。您无法知道位字段是如何对齐的,或者中间是否有填充位/字节,除非您深入阅读了编译器后端文档。还有字节序、位顺序等:无数未指定或实现定义的行为。最好的解决方案是根本不使用位域。
    • 当我创建一个位域实例GAIN_REG_st GAIN_x 并通过引用传递GAIN_x 时,不是我只是传递一个指向位域的指针吗?所以对齐问题不会成为问题,因为我实际上并没有在内存中移动位域?
    • 我不同意 Lundin 的评论。 C 编译器应该可以处理位字段并将指针传递给它们。如果您尝试将位字段转换为其他类型(例如unsigned char 数组),则可能适用 Lundin 的 cmets。
    • @Craig 根据该位字段的性质判断,它将在“原始布尔缓冲区”之外使用。所以所有提到的问题可能存在也可能不存在。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-05
    • 2017-02-10
    • 2023-03-08
    • 1970-01-01
    • 1970-01-01
    • 2013-11-13
    • 2011-12-07
    相关资源
    最近更新 更多