为什么要在函数头中声明C数组参数的大小?

jogvjijk  于 2024-01-06  发布在  其他
关注(0)|答案(5)|浏览(171)

有谁能告诉我为什么我应该在函数头中指定C数组参数的大小?例如:

void foo (int iz[6]) { iz[42] = 43; }

字符串
有:

int is[2] = {1,2,3};


我们得到了一个有用的错误。也许它对注解/文档有帮助?

wqsoz72f

wqsoz72f1#

有谁能告诉我为什么我应该在函数头中指定C数组参数的大小?例如:
void foo(const char sz[6]){ sz[42] = 43; }
IMO,你不应该这样做。当你试图将一个数组传递给一个函数时,真正传递的是一个指向数组开头的指针。因为函数接收的是一个指针,所以最好将它写得显式:

void foo(char const *sz)

字符串
然后,因为现在很清楚函数没有给出大小的线索,所以添加它作为一个单独的参数:

void foo(char const *sz, size_t size)

pxq42qpu

pxq42qpu2#

这样做的唯一有意义的原因是为了文档的目的-告诉未来的用户函数期望接收至少有这么多元素的数组。但即使是这样也是一个约定的问题-你必须事先与其他用户达成一致。语言(编译器)无论如何都会忽略这个大小。你的函数声明等价于void foo(int iz[])void foo(int *iz)
使其对编译器有一定意义的唯一方法是将其声明为

void foo (int iz[static 6])

字符串
它向编译器承诺数组将至少有6个元素,这意味着编译器将能够使用该假设优化该代码。此外,如果您真的想采用上面提到的约定,则使用static声明数组参数大小更有意义,因为语言显式定义了此构造的语义。
你说的“我们得到了一个有用的错误”是什么意思,我不清楚。

int is[2] = {1,2,3};
is[42] = 42;


不包含任何违反约束的行为。它会产生未定义的行为,但在编译期间不需要产生诊断消息。换句话说,不,我们不会从中得到任何“有用的错误”。

q9rjltbz

q9rjltbz3#

这是一个注解。数组被降级为函数参数中的指针。注解仍然是有用的,即使编译器不读取它们。

uyto3xhc

uyto3xhc4#

这是一个有用的注解,当你想告诉客户端代码,它必须传递一个定义大小的数组,即:

void foo(const char bar[5]);
/* It is expected that foo function receives an array of size 5 */

字符串
然而,文档并不能代替代码检查:

void foo(const char bar[5])
{
    if (!bar) error();
    if (strlen(bar) != 4) error();
    /* ... */
}

w8ntj3qf

w8ntj3qf5#

Imho,在现代编译器版本(如现代gcc),以前的答案现在是错误的。事实上,在这些编译器的现代版本中,在函数头中指定的arraw的大小被编译器用来通过非常有用的警告。
示例:在gcc 12上,如果指定:

int f(char string[32])

字符串
然后调用函数:

int main{
char paul[6]="paul"
f(paul);
}


编译器将通过一个警告,说你可以在f中使用32个字符,但你只指向一个6字节的内存空间。
于是:在现代编译器中,它有助于精确你的意图,并让编译器对你的意图和你所编码的内容的一致性进行额外的检查。
完整示例:

#include <stdio.h>

void f(char string[32])
{
        printf("%s\n",string);
}

int main(){
        char paul[5]="paul";
        f(paul);
}


威尔通过:

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])
      |      ^


简单调用gcc test.c-o my_executable

相关问题