testi.c: In function ‘main’:
testi.c:12:9: warning: ‘f’ accessing 32 bytes in a region of size 5 [-Wstringop-overflow=]
12 | f(paul);
| ^~~~~~~
testi.c:12:9: note: referencing argument 1 of type ‘char[32]’
testi.c:5:6: note: in a call to function ‘f’
5 | void f(char string[32])
| ^
5条答案
按热度按时间wqsoz72f1#
有谁能告诉我为什么我应该在函数头中指定C数组参数的大小?例如:
void foo(const char sz[6]){ sz[42] = 43; }
IMO,你不应该这样做。当你试图将一个数组传递给一个函数时,真正传递的是一个指向数组开头的指针。因为函数接收的是一个指针,所以最好将它写得显式:
字符串
然后,因为现在很清楚函数没有给出大小的线索,所以添加它作为一个单独的参数:
型
pxq42qpu2#
这样做的唯一有意义的原因是为了文档的目的-告诉未来的用户函数期望接收至少有这么多元素的数组。但即使是这样也是一个约定的问题-你必须事先与其他用户达成一致。语言(编译器)无论如何都会忽略这个大小。你的函数声明等价于
void foo(int iz[])
和void foo(int *iz)
。使其对编译器有一定意义的唯一方法是将其声明为
字符串
它向编译器承诺数组将至少有6个元素,这意味着编译器将能够使用该假设优化该代码。此外,如果您真的想采用上面提到的约定,则使用
static
声明数组参数大小更有意义,因为语言显式定义了此构造的语义。你说的“我们得到了一个有用的错误”是什么意思,我不清楚。
型
不包含任何违反约束的行为。它会产生未定义的行为,但在编译期间不需要产生诊断消息。换句话说,不,我们不会从中得到任何“有用的错误”。
q9rjltbz3#
这是一个注解。数组被降级为函数参数中的指针。注解仍然是有用的,即使编译器不读取它们。
uyto3xhc4#
这是一个有用的注解,当你想告诉客户端代码,它必须传递一个定义大小的数组,即:
字符串
然而,文档并不能代替代码检查:
型
w8ntj3qf5#
Imho,在现代编译器版本(如现代gcc),以前的答案现在是错误的。事实上,在这些编译器的现代版本中,在函数头中指定的arraw的大小被编译器用来通过非常有用的警告。
示例:在gcc 12上,如果指定:
字符串
然后调用函数:
型
编译器将通过一个警告,说你可以在f中使用32个字符,但你只指向一个6字节的内存空间。
于是:在现代编译器中,它有助于精确你的意图,并让编译器对你的意图和你所编码的内容的一致性进行额外的检查。
完整示例:
型
威尔通过:
型
简单调用gcc test.c-o my_executable