cri*_*sls 5 c misra opaque-pointers incomplete-type
此问题涉及遵循 MISRAC:2012 指南的 ISO C99 编码。
\n\n我正在寻找有关 Dir 4.8 \xe2\x80\x9c 的指导如果指向结构或联合的指针从未在翻译单元内取消引用,则该对象的实现应与 Dir 4.12 \ 一起隐藏\xe2\x80\x9d xe2\x80\x9c不应使用动态内存分配\xe2\x80\x9d。
\n\n在 C 中实现抽象数据类型时,通常使用句柄来引用 ADT,该句柄是指向描述 ADT 内部状态的结构的指针。这可以根据 Dir 4.8 使用不透明指针来完成,其优点是内部细节对用户保持隐藏。
\n\n通常,可能存在多个 ADT,因此必须有一种方法来创建多个句柄。这可以通过在初始化函数中为句柄引用的内部细节分配内存来解决,但是,这在 Dir 4.12 下是不允许的。
\n\n另一种选择是初始化例程接收用户提供的指向静态分配句柄的指针,但是,这不能使用不透明指针来完成。
\n\n我在下面说明这个问题。
\n\n Module.h \n\n struct module; \n typedef struct module module_t; /* Module handle is only available to the world as an incomplete type. This allows us to satisfy MISRAC 2012 Dir 4.8.*/\n\n Module.c\n\n #include "module.h"\n struct module\n {\n uint8_t value;\n };\n module_t* module_get_a_handle(void)\n {\n return (module_t*)malloc(sizeof(struct module)); /* MISRAC 2012 Dir 4.12 disallows dynamic memory allocation.*/\n }\n\n User.c\n\n #include "module.h"\n module_t* module_handle;\n module_handle = module_get_a_handle();\nRun Code Online (Sandbox Code Playgroud)\n\n此问题中也描述了该问题\n不透明数据类型的静态分配,但未根据 MISRAC:2012 指南进行讨论。
\n\n所描述的一种解决方案是使用可供客户端代码使用的静态分配的句柄池。该解决方案似乎在技术上是合规的;不过,这里似乎仍然存在动态内存分配的概念。我认为,虽然句柄是静态分配的,但编译器在编译期间无法确定是否有足够的句柄可供软件正常运行。
\n\n我对这个问题的解决方案是围绕 Dir 4.8 编写一个偏差,并使用非不透明指针和强大的命名约定,让用户清楚地知道 ADT 的内部细节不得更改。
\n\n我很好奇是否有一个被广泛接受的方法来解决这个问题,满足 Dir 4.8 和 Dir 4.12,并且不违反任何其他 MISRAC:2012 规则。如有任何意见,我们将不胜感激。
\n看来您已经理解了问题和解决方案:在每个 ADT 内部使用静态内存池。
不过,这个池需要限制在某个最大限制,这应该是硬编码的。本质上,您将把池实现为static文件范围内的缓冲区,并使用计数器变量跟踪“分配”的大小。对于添加的每个项目,您都会根据最大限制检查计数器。
如果您的空间不足,您的程序会知道这一点,并且能够以安全的方式处理该错误。不过,永远不应该有任何原因导致空间不足。这意味着您存在设计错误。几乎可以肯定,您应该能够确保在编译时不会耗尽空间。或者,如果没有,至少在代码覆盖率测试期间。
指令 4.12 关注堆上的动态内存分配malloc/free。使用这些函数和堆是术语动态内存分配的 C 事实上标准定义。这并不意味着其他任何事情。
动态分配存在多个问题:不确定的分配时间、分段、内存泄漏等。
只要程序行为保持确定性,“动态性”本身就不是问题。安全标准始终关注堆上的动态内存分配,因为它意味着非确定性行为,这是安全关键软件设计中的一个大罪。
对于许多常见的嵌入式系统(例如裸机/RTOS 微控制器应用)来说,动态分配根本没有任何意义。
所以静态内存池并不是“动态内存分配”。否则,堆栈的使用也将被视为“动态内存”,并且根本不可能编写任何有用的软件。