我想确保这种类型的代码
void f1 (int32_t p[10]);
void f2 (int32_t *p);
void b ()
{
int_32_t a[10];
f1(a);
f2(a);
}
当有人编码时,不会发生,因为当使用f2()时,您可能会丢失有关数组边界的信息。这是MISRA标准规则之一。
但AST-dump在2个函数声明之间没有区别:
|-FunctionDecl 0x2204140 <test.cpp:3:1, col:23> f1 'void (int32_t *)'
| -ParmVarDecl 0x2204040 <col:10, col:22> p 'int32_t *'
|-FunctionDecl 0x2204280 <line:4:1, col:20> f2 'void (int32_t *)'
| -ParmVarDecl 0x2204200 <col:10, col:19> p 'int32_t *'
我猜Clang确实记录了数组(10)的大小,但AST-dump似乎告诉了相反的结果。
有没有办法区分?
答案 0 :(得分:10)
这个问题似乎是基于一种误解。这个函数声明
void f1 (int32_t p[10]);
与
完全相同void f1 (int32_t* p);
在两种情况下,参数都是指针。任何地方都没有尺寸信息。
请注意,在C ++中,您可以拥有对特定大小的数组的引用的函数参数。例如,
void f3(int (&p)[10]);
此签名与示例中显示的f1
和f2
不同。
答案 1 :(得分:1)
我猜Clang确实记录了数组(10)的大小,但AST-dump似乎告诉了相反的结果。
你的猜测错了。
有没有办法区分?
没有。根据C和C ++的规则没有区别。见http://www.c-faq.com/aryptr/aryptrparam.html
答案 2 :(得分:1)
我认为你从错误的一端攻击这个问题。功能的声明是等效的,但这不是问题,因为您之后的规则适用于呼叫站点。在调用站点,您当然知道该数组被传递给一个带有指针的函数,并且不会在另一个参数中获取数组大小。从调用网站的角度来看,f1
和f2
调用在语义上都是相同的。他们同样安全或不安全。
C标准并不要求编译器在将参数传递给函数时保留数组边界信息。如果函数的参数声明中有任何数组边界,则它们仅供人类使用。根据MISRA,f1
和f2
电话完全相同,而且它们都是错误的。您需要显式传递指针和数组大小。
如果您希望对使用指针或小于给定大小的数组调用f1
进行特殊诊断,则必须修改解析器并向AST添加自定义注释。然后,您的分析仪可以获取该信息。
对于任何这些都没有任何意义,当静态代码分析表明参数被索引超过f1
内的边界时,您还需要添加诊断。