为什么在MISRA:2012中需要function原型?

我想知道为什么MISRA要求function原型:2012。 在下面的示例中,两个原型并不是必需的。

#include  #include  // >>> Truly useless in my opinion void display(void); int main(void); // <<< void display(void) { printf("Hello World!\n"); } int main() { display(); return EXIT_SUCCESS; } 

我在这里可以阅读的基本原理对我来说不是很清楚。 例如,如果main在声明之前尝试访问display ,则编译器或静态分析器将引发错误:声明之前使用的函数显示。

换句话说,为这个MISRA规则创建偏差是个好主意吗?

void display(void); 是一个函数转发声明。 它有原型格式。

如发布的链接所示,函数原型是一个函数声明,其中包含指定的所有参数的类型。 如果没有参数,则参数列表必须是(void) (无参数)而不是() (任何参数)。

确切的规则8.2说:

规则8.2函数类型应采用带有命名参数的原型forms

提供的理由(读它,它是相当不错的)提到这是为了避免旧的K&R和C90程序,其中没有指定所有参数。 只要函数声明中的参数类型不与函数定义中的参数类型冲突,C99在某种程度上仍允许这种情况。

从本质上讲,该规则旨在禁止这些function:

 void func1 (x) // K&R style int x; {} void func2(x) // sloppy style {} 

所有参数(如果有)必须指定类型和名称。

但是 ,我在MISRA-C中找不到任何要求您为每个函数编写函数声明的内容。 这意味着您的示例代码在有或没有函数声明的情况下符合此MISRA规则。


虽然正如我在之前的回答中提到的那样,编写没有函数声明的.c文件(原型格式)是一种草率的做法。 如果需要按特定顺序调用函数,则应通过程序设计,函数命名和注释/文档使其显而易见。 不是它们碰巧在.c文件中声明的顺序。

在.c文件中声明函数的源代码行与该函数的行为/用途之间不应该存在紧密耦合。

相反,应该按照逻辑上有意义的顺序定义函数。 编写.c文件的一种常用方法是在.c文件的顶部保留所有公共函数,这些函数在.h文件中都有函数声明。 然后让内部函数(具有static /内部链接的函数)位于底部。 该模型需要所有内部函数的函数声明。 另一个选择是将所有内部函数放在最顶层,将公共函数放在底部。 只要你保持一致,要么就好了。

最重要的是, 如果.c文件中的函数定义被重新排序,它不应该破坏程序或导致编译器错误 。 确保这一点的最简单方法是始终为程序中的每个函数提供函数声明。

请注意,文件顶部的函数声明根本不是“真正无用”,因为它们提供了C文件中存在的所有函数的快速摘要。 这是一种编写自我记录代码的方法。


请注意,作为特殊情况,C标准不允许main()的原型。

请注意,此外,规则8.7和8.8禁止您使用void display(void)而不使用static ,因为该函数仅用于一个转换单元。

如果不声明该函数,任何函数调用都将为每个参数调用default argument promotions ,因为它被认为该函数具有C89标准的语义。

 Case 1: 

考虑一个调用f(5),其中函数的参数是double类型。 f的代码将5视为double,而默认的arith促销仅传递整数。

丢失包含声明的头文件可能会使代码传递整数,实际上是将它们视为导致seg错误的指针的函数。 这是一个具体的例子:

 Case 2: 

假设您要使用函数strtok并且不包含带有声明的头文件string.hchar *strtok(char *str, const char *delim)

现在你错误地认为分隔符’A’而不是“A”。 因此,如果您忘记了签名但请记住参数的含义,如果您不包含标题,代码将在没有警告的情况下编译,当然strtok的代码会考虑您的char’A’(以整数转换) (= 95))作为实际论点。 代码认为它是一个指向字符串的指针,并将尝试从完成segfault的位置95访问指针。

 Case 3: 

这是另一个代码段的典型代码,它在某些体系结构上进行了段落错误 – 即使你没有犯任何错误,它仍然是段错误的。

 char *subtoken; subtoken = strtok(str, delim, &saveptr); 

在这种情况下,函数strtok (缺少来自string.h的声明)被认为返回一个int ,因此从int->char*进行隐式转换。 如果int用32位表示而指针用64位表示,那么suboken的值显然是错误的并且会产生seg错误。