我正在做一个嵌入式项目(PowerPC目标,Freescale Metrowerks Codewarrior编译器),其中的寄存器是内存映射的,并在很好的位域中定义,以便轻松地旋转单个位标志。
目前,我们正在使用此功能清除中断标志并控制数据传输。虽然我还没有注意到任何bug,但我很好奇这是否安全。有没有什么方法可以安全地使用位域,或者我需要把每个位域都包装在DISABLE_INTERRUPTS中……ENABLE_INTERRUPTS?
需要说明的是: micro提供的报头具有如下字段
union {
vuint16_t R;
struct {
vuint16_t MTM:1; /* message buffer transmission mode */
vuint16_t CHNLA:1; /* channel assignement */
vuint16_t CHNLB:1; /* channel assignement */
vuint16_t CCFE:1; /* cycle counter filter enable */
vuint16_t CCFMSK:6; /* cycle counter filter mask */
vuint16_t CCFVAL:6; /* cycle counter filter value */
} B;
} MBCCFR;我假设在位域中设置一个位不是原子的。这是一个正确的假设吗?编译器实际上会为位域生成什么类型的代码?自己使用R(原始)字段执行掩码可能更容易记住操作不是原子的(很容易忘记像CAN_A.IMASK1.B.BUF00M = 1这样的赋值不是原子的)。
非常感谢您的建议。
发布于 2010-07-21 21:49:50
原子性取决于目标和编译器。例如,AVR-GCC尝试检测位访问,并在可能的情况下发出位设置或清除指令。检查汇编程序的输出以确保...
编辑:这是一个直接从PowerPC上获取原子指令的资源:
http://www.ibm.com/developerworks/library/pa-atom/
发布于 2010-07-21 21:50:36
假设设置位域不是原子的,这是正确的。C标准对如何实现位域并不特别清楚,不同的编译器对位域的实现方式也各不相同。
如果你真的只关心你的目标架构和编译器,反汇编一些目标代码。
通常,您的代码将实现所需的结果,但效率远低于使用宏和移位的代码。也就是说,如果您不关心这里的性能,那么使用位字段可能更具可读性。
如果您担心将来的程序员(包括您自己)会感到困惑,那么您可以为原子的位编写一个setter包装器函数。
发布于 2010-07-21 21:56:58
是的,你的假设是正确的,因为你可能不会假设原子性。在特定的平台上,您可能会将其作为额外服务获取,但在任何情况下都不能依赖它。
基本上,编译器会为您执行掩码和其他操作。他也许能够利用转角案例或特殊指示。如果你对效率感兴趣,看看你的编译器生成的汇编程序,通常它是非常有指导意义的。作为一个经验法则,我想说现代编译器生成的代码与中等编程工作的效率一样高。对于你的特定编译器来说,真正深入的比特转换可能会给你带来一些好处。
https://stackoverflow.com/questions/3299897
复制相似问题