传递数组时,在C中的函数参数中强制使用数组大小​​

时间:2019-05-16 20:57:25

标签: c arrays parameter-passing

上下文

在C语言中,我有一个将数组作为参数的函数。此参数用作此函数的输出。输出总是相同的大小。我会:

  • 使任何阅读代码的人都清楚所需的大小(尽管已经在函数注释中了),
  • 理想情况下,编译会输出警告或错误,因此我可以防止在编译时(而不是运行时)出现问题。

潜在的解决方案

我在这里找到了:https://hamberg.no/erlend/posts/2013-02-18-static-array-indices.html,看起来很像解决方案,但是如果我尝试传递比所需大小小的数组,则在编译过程中将不会收到警告或错误。

这是我完整的程序main.c:

void test_array(int arr[static 5]);

int main(void)
{
    int array[3] = {'\0'};

    test_array(array); // A warning/error should occur here at compilation-time
                       // telling me my array does not meet the required size.

    return 0;
}

void test_array(int arr[static 5])
{
    arr[2] = 0x7; // do anything...
}

与此博客相反,我通过以下命令使用gcc(版本7.4.0)代替了clang:

gcc -std=c99 -Wall -o main.out main.c

在我的代码中,我们可以看到test_array()函数需要一个5个元素的数组。我要通过一个3要素之一。我希望编译器提供有关此的消息。

问题

在C语言中,如何强制将函数参数作为给定大小的数组?如果不是这样,在编译时应该会引起注意。

2 个答案:

答案 0 :(得分:6)

如果传递指向数组的指针而不是指向其第一个元素的指针,则会收到不兼容的指针警告:

void foo(int (*bar)[42])
{}

int main(void)
{
    int a[40];
    foo(&a);  // warning: passing argument 1 of 'foo' from incompatible pointer type [-Werror=incompatible-pointer-types]
    // note: expected 'int (*)[42]' but argument is of type 'int (*)[40]'

    int b[45];
    foo(&b);  // warning: passing argument 1 of 'foo' from incompatible pointer type [-Werror=incompatible-pointer-types]
    // note: expected 'int (*)[42]' but argument is of type 'int (*)[45]'
}

使用-Werror进行编译以使其出错。

godbolt

答案 1 :(得分:4)

要测试要传递的数组(不是指针)的大小至少为5个元素,可以使用Static_assert,并可以通过预处理器宏插入必要的_Static_assert。 / p>

在函数声明之后,插入:

#define test_array(arr) \
    do \
    { \
        _Static_assert(sizeof (arr) / sizeof *(arr) >= 5, "Array is too small."); \
       test_array(arr); \
    } while (0)

do … while (0)是定义宏的一种经典方法,该宏在语法上类似于一条语句,因此可以跟随;并按照if语句的预期进行流动,这样。

在定义函数之前,插入:

#undef test_array

(如果随后使用该函数有更多用途,则必须插入#define的另一个副本。或者,可以在源文件的早期定义该函数,然后在#define之后定义,以消除任何需要其他#undef#define指令。)

通常,这样的代码不太可能有用,因为程序经常将指针传递到数组的第一个元素(或指向数组中间的元素),并且无法测试空间中有多少个元素指针指向。因此,这仅在我们需要要作为参数给出的数组的代码中有用。该代码没有强制执行该要求。