我正试图从我的代码中删除规则11.3。
样本代码:
static int32_t
do_test(const char *cp)
{
const char *c = cp;
const int32_t *x;
x = (const int32_t *)cp;
return *x;
}
我希望 *c和 *x的值相同,即使代码正在编译并给出正确的值,“x =(int32_t *)cp;“导致违反11.3和11.8
违反规则11.3:具有指针类型的对象不应转换为指向不同对象类型的指针。
我尝试过使用void指针,但结果与我预期的不一样,而且还导致了额外的违规。
有办法消除这些违规行为吗?
在MISRA C 2012文档中,他们提到该规则有一个例外,因为允许将指向对象类型的指针转换为指向对象类型char、signed char或unsigned char之一的指针。该标准保证指向这些类型的指针可用于访问对象的单个字节。
由于字符类型,忽略Dir 4.6。
3条答案
按热度按时间uxhixvfz1#
你很幸运你使用的是MISRA-C,因为这段代码充满了bug,你不能用强制类型转换来消除bug。
指向一个对象类型的指针可以转换为指向另一个对象类型的指针。如果结果指针没有与引用类型正确对齐,则该行为未定义。
您的假设“标准保证指向这些类型的指针可以用于访问对象的各个字节。”是正确的:作为一个特殊的例外,C允许你从指向x的指针转换为指向char的指针,然后通过char指针访问数据。
您的代码 * 不 * 访问单个字节;你正在走另一条路,从一个字符数组到一个32位类型。这是不允许的。参见What is the strict aliasing rule?。
正确的代码,这应该是确定与C语言和MISRA-C:
这种移位版本总是首选的,因为它与字节序无关,因此可移植。强制转换为
uint32_t
对于防止8/16位系统上的隐式提升是必要的,而且您永远不应该对有符号类型进行移位。szqfcxe22#
如果您觉得有必要避免显式强制转换,您总是可以执行
memcpy
:使用内置
mempcy
的优化编译器,这应该与return *(int32_t*)cp;
(您的代码,编写得更简洁)一样高效。请记住,在任何一种情况下,仅当传入的
cp
值指向有效的int32_t
对象时,才定义代码。如果memcpy因为
char*
到void*
的隐式转换而不能正常工作,您可以将其替换为定制的普通实现的void charwise_memcpy(char *Dest, char const *Src, size_t Sz);
或等效的for
循环。3mpgtkmj3#
原始代码可能导致未定义的行为:
如果
int32_t
在平台上有对齐要求,而cp
没有针对该要求正确对齐,则行为是未定义的。一般来说,我不是MISRA的粉丝,但是这个例子看起来很合理。即使你碰巧在一个没有对齐要求的平台上(即使在嵌入式开发中也不太可能),这个代码也是不可移植的,如果你转移到一个有对齐要求的CPU上,它可能会开始崩溃。
一个好的解决方案是使用定义良好的
memcpy
: