我使用各种微控制器架构/字长为嵌入式系统开发固件,并在可能的情况下尽量强调可移植性。我的问题是关于生成/应用安全且可移植的位掩码和标志,对于任何非通用代码,情况如何?
位掩码
#define MASK_8_V1(x) ((x) & 0xFF)
#define MASK_8_V2(x) ((x) & 0x00FF)
a = MASK_8_V1(b)
a = MASK_8_V2(b)
是否总是保证除b的低8位外所有位都为零的a的宽度值?这两个版本之间有什么区别,因为如果有必要对它们进行签名扩展?
标志
#define GEN_FLAG_16(x) ((0xFFFF) & ((unsigned) 1 << (x)))
#define GEN_FLAG_32(x) ((0xFFFFFFFF) & ((unsigned long) 1 << (x)))
如果我需要一个通用宏来生成标志常量,是否会始终为列出的宽度生成一个标志常量?
两个都
#define CHECK_FLAG_16(x, y) ((x) & GEN_FLAG_16(y))
#define CHECK_FLAG_32(x, y) ((x) & GEN_FLAG_32(y))
if(CHECK_FLAG_16(a, b))
{
// Do something.
}
结合前面的场景,如果设置了b的原始值中的所需位,它将始终执行内部代码吗?
对于所有情况,假定:
编辑那些提到的用法stdint.h
:最近我遇到一个问题,我们需要将我已经写过的串行协议处理程序移植到另一个微控制器系列中,只是发现RAM不可字节寻址。我们最终删除了uint8_t的所有使用,并进行了修改以使用16位可寻址内存。这让我想知道是否可以使用本机C类型以不同的方式实现它,以避免以后进行修改。我的问题间接地来自那个问题。
是否总是保证除b的低8位外所有位都为零的a的宽度值?
是的。
但是,最终的宏类型可能会有所不同,具体取决于类型b
。这可能会导致可移植性问题。因此,最好将结果转换为预期的类型,例如uint32_t
。
两个版本之间有什么区别
不,它们是等效的。
如有必要,应延长签收时间
在带符号类型上使用按位运算符通常没有任何意义。
如果我需要一个通用宏来生成标志常量,是否会始终为列出的宽度生成一个标志常量?
是的,但是结果将根据int或long的大小而具有不同的类型。
我最近遇到一个问题,我们需要将我已经写过的串行协议处理程序移植到另一个微控制器系列中,只是发现RAM不可字节寻址。
那主要是编译器的问题。同样,还不清楚uint8_t
在这样的系统上怎么会出现问题,总是存在隐式整数提升。听起来好像您遇到了一些算法问题,也许是使用uint8_t*
指针的代码或类似的代码。
从脚步来看,完全可移植的代码如下所示:
#define MASK8_32(x) ((uint32_t)(x) & 0xFFul)
#define GEN_FLAG_16(x) (uint16_t)( 0xFFFFu & (1u << (x)) )
#define GEN_FLAG_32(x) (uint32_t)( 0xFFFFFFFFu & (1ul << (x)) )
现在,大多数潜在的int大小和隐式类型提升依赖关系已被删除。
这里主要的可移植性问题是:
int
和long
这样的代码是不可移植的,因为这些类型可具有任何尺寸。使用stdint.h中的固定宽度整数类型将解决许多此类问题。事实证明,所有这些问题都可以通过MISRA-C解决。我建议购买MISRA-C:2012并阅读以用于教育目的。
作为边注,如代码a = OBSUCRE_MACRO(b);
是少得多可读不是像代码a = b & 0xFF;
。因为您始终可以假设读者是C程序员,因此知道C语言,但不知道您的私有秘密宏语言。
此外,类似函数的宏是不安全的,应尽可能避免使用。
因此,我首先质疑这些宏有什么用。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句