我有一个名为typedef struct的字符。
typedef struct {
unsigned int a : 1;
unsigned int b : 1;
unsigned int c : 1;
unsigned int d : 1;
unsigned int o : 1;
unsigned int p : 1;
unsigned int q : 1;
unsigned int x : 1;
} Character;
static Character tempChar;
void writeVar(const uint8_t *pData)
{
tempChar.a = pData[0] >> 5;
...
}当我试图将一个uin8_t变量(值为0或1)分配给这些位字段之一时,我违反了MISRA规则10.6,其中规定:
复合表达式的值不应赋值给具有更广泛基本类型的对象。
有没有一种在不违反MISRA的情况下为uint8_t分配位字段的方法?
发布于 2020-01-27 10:09:58
如果需要的话,表达式pData[0] >> 5中的两个操作数将是到int (这将发生在pData[0]中)。
表达式的结果是一个int。
晋升和从int到unsigned int的转换,虽然在正常情况下是完全有效和罚款的,但足以让非常严格的MISRA抱怨。
简单的解决方案(如注释所示)是使用强制转换将pData[0]显式转换为unsigned int。
发布于 2020-01-27 16:06:06
这里的核心问题与MISRA无关,而与试图将值存储在位字段中的特定时隙有关。您无法知道您的位字段布局实际上是如何在内存中结束的,因为这在C标准中没有定义。
您的位字段是在MS字节还是LS字节中分配8个值位?它是按照规定取得的,还是不符合?点位顺序是什么?没人知道。第一步是去掉位字段.
第2步是摆脱任何unsigned int,并使用uint16_t/uint32_t。
特别是Misra-C10.6,反对隐式转换到更广泛类型的规则总是被误导的。这条规则使用的基本原理是防止人们编写像uint32_t u32 = u16a + u16b;这样的代码,并认为=的u32操作数在某种程度上意味着操作将在32位而不是16位上执行。但在8/16位系统上,它是用16位算术执行的,可能会出现溢出/环绕。
现在,对有符号类型进行位转换总是一个非常糟糕的主意。pData[0]被隐式提升到被签名的int。还有其他米斯拉规则来处理这个问题,而不是你引用的那条。
不管米斯拉如何,你都应该养成一个习惯,在没有符号的类型上执行你的轮班。“在这种情况下这并不危险”是一个黯淡的理由。这意味着始终编写(uint32_t)pData[0] >> 5,转换之前应该应用强制转换,而不是在转换之后。这消除了与未定义的行为、左移位和可能的算术右移位等有关的所有不确定性。让优化器考虑操作数的实际使用大小。
发布于 2020-01-27 10:09:17
因为这个原因,我觉得米斯拉·C太复杂了。不管怎样,你没说你想直接分配它。如果是这样的话,你可以采取以下措施:
typedef union {
struct {
unsigned int a : 1;
unsigned int b : 1;
unsigned int c : 1;
unsigned int d : 1;
unsigned int o : 1;
unsigned int p : 1;
unsigned int q : 1;
unsigned int x : 1;
};
uint8_t u8Value;
} Character;并通过访问tempChar.u8Value而不是位字段来设置这些值。例如,
tempChar.u8Value |= (1 << 0);将tempChar.a设置为1。
这仍将保持代码的整洁(可读性)在同样程度上。例如,
if(1 == tempChar.a)
{
// Some code
}https://stackoverflow.com/questions/59928364
复制相似问题