如何编写完全兼容MISRA:2012的memcpy函数?
我编写了这个如何编写完全兼容MISRA:2012的memcpy函数?,c,void-pointers,misra,qualifiers,C,Void Pointers,Misra,Qualifiers,我编写了这个memcpy函数,但我仍然需要禁用规则11.5和11.8。是否有完全兼容MISRA:2012的解决方案 #pragma cstat_suppress="MISRAC2012-Rule-21.6" // Uses of stdio.h were found. #include <stdio.h> #include <stdint.h> #include <string.h> #include <stdlib.h> extern int
memcpy
函数,但我仍然需要禁用规则11.5和11.8。是否有完全兼容MISRA:2012的解决方案
#pragma cstat_suppress="MISRAC2012-Rule-21.6" // Uses of stdio.h were found.
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
extern int main(void);
static int_least8_t _memcpy(void *dst, const void *src, const size_t length)
{
#pragma cstat_disable="MISRAC2012-Rule-11.5" // A conversion from a pointer to void into a pointer to object was found.
int_least8_t* destination = (int_least8_t*)dst;
#pragma cstat_disable="MISRAC2012-Rule-11.8" // A cast that removes a const or volatile qualification was found.
const int_least8_t* source = (int_least8_t*)src;
#pragma cstat_restore="MISRAC2012-Rule-11.5","MISRAC2012-Rule-11.8"
for (size_t i = 0; i < (length / sizeof(int_least8_t)); i++)
{
destination[i] = source[i];
}
return 0;
}
int main(void)
{
int32_t src[32];
int32_t dst[32];
(void)memset(src, 0xff, sizeof(src));
(void)_memcpy(dst, src, 128);
for (size_t i = 0; i < (sizeof(src) / sizeof(src[0])); i++)
{
(void)printf("%d <=> %d\n", src[i], dst[i]);
}
return 0;
}
找到stdio.h的用法。
#包括
#包括
#包括
#包括
外部内部主(无效);
静态内部最小8个内存(无效*dst,常量无效*src,常量大小长度)
{
#pragma cstat_disable=“MISRAC2012-Rule-11.5”//找到从指向void的指针到指向对象的指针的转换。
int_least8_t*目的地=(int_least8_t*)dst;
#pragma cstat_disable=“MISRAC2012-Rule-11.8”//A找到删除常量或volatile限定的强制转换。
const int_least8_t*源=(int_least8_t*)src;
#pragma cstat_restore=“MISRAC2012-Rule-11.5”、“MISRAC2012-Rule-11.8”
对于(大小i=0;i<(长度/大小f(至少8);i++)
{
目的地[i]=源[i];
}
返回0;
}
内部主(空)
{
int32_t src[32];
int32_t dst[32];
(void)memset(src,0xff,sizeof(src));
(无效)_memcpy(dst,src,128);
对于(size_t i=0;i<(sizeof(src)/sizeof(src[0]);i++)
{
(无效)printf(“%d%d\n”,src[i],dst[i]);
}
返回0;
}
我使用IAR作为编译器,使用C-STAT进行静态分析 您无法使用标准格式编写
memcpy
,并且完全符合MISRA。正如您所注意到的,MISRA不允许restrict
。但也有规则11.5
关于从指针到void再到指针到类型的强制转换的规则11.5在实践中太麻烦了。这是一条建议性的规则,所以我将跳过它。您不需要提出偏差
然而,关于淘汰资格赛的规则11.8是合理的(并且是必需的)。在这种情况下,没有理由这样做。您的代码中有一个由MISRA阻止的错误。将代码更改为
const int_least8_t* source = (const int_least8_t*) src;
补充说明:
- 您不需要向
提供转发声明main()
- MISRA-C不允许使用stdio.h
- 避免声明以下划线开头的标识符,请参阅C11 7.1.3
- 在这里使用
没有明显的好处。此外,有符号类型也有问题。我会用int\u least8\t
来代替uint8\t
memcpy
没有类型安全性,就是这样。此外,memcpy
本身在确定对象的有效类型方面起着作用。但另一条规则的理由并不充分。无论如何,您的代码不是标准库memcpy
,因此该规则不适用。以下划线开头的名称保留用于实现。应用程序代码不能使用它们。作为旁注:我为什么不使用标准库的memcpy
,它很可能是高度优化的,但是一些自制的、速度最慢的版本?为什么\u memcpy
返回0?这对于任何希望它像标准的memcpy()
一样工作的人来说都是一个惊喜。而且绝对没有必要像这样抛弃常量:const int\u least8\u t*source=(const int\u least8\u t*)src代码>应该可以。使用int\u least8\t
也可能存在对齐问题。无法保证要复制的内存与类型对齐。我会说使用无符号字符
,因为在任何情况下它都可能与uin8\u t
不同,那么使用无符号字符
将是正确的答案。@Persixty MISRA-C鼓励使用stdint.h
,如果不使用stdint类型,你需要一个好的理由。这不是一个很好的理由-如果您的系统不支持uint8\t
,但有16位字符,那么您的DSP功能就不正常了。你应该用汇编语言而不是C语言来编写。对于普通的C语言程序来说,绝对没有必要为那些古怪的、异国情调的、过时的DSP提供可移植性。这样做的人只是在浪费每个人的时间。为现实世界的主流计算机架构提供可移植性就足够了。我没有意识到这一点。我同意这是一个疯狂的理论,在汽车行业的某个地方,有人使用的不是8位字节的东西(但我在此不把它超过雷诺或菲亚特)。面对这条(坦率地说是严厉的)规则,我没有什么好的理由。但对齐点仍然存在。将void*
强制转换为对齐类型还有一个问题您没有标记。@将任何uint8\t
(或字符类型)复制到同一类型的另一个变量完全可以。当您尝试以其他类型访问指向的数据时,会出现对齐问题,在这种情况下,您也会遇到严格的别名问题,这是MISRA不允许的。不管怎么说,不一致本身并不是“my_memcpy”的问题,而是调用者的问题。除此之外,基于对齐字长的拷贝会在某些系统上产生更快的代码,而不是逐字节。uint\u fast8\t
可能需要解决对齐问题uint\u fast8\t
是最快的类型,至少有8位。可能更宽,并在优化平台上对齐。它最有可能使用对齐的指令——因为它的广告发布速度一样快!您可以编写my\u memcpy()
来执行第一个奇数字节作为uint8\u t
,正文作为更宽的类型,最后一个字节作为uint8\u t
。