9

一个非常简单的C语言程序:

#include <stdio.h>
#include <stdlib.h>

void process(int array[static 5]){
    int i;
    for(i=0; i<5; i++)
        printf("%d ", array[i]);
    printf("\n");
}

int main(){

    process((int[]){1,2,3});
    process(NULL);

    return 0;
}

我编译它:gcc -std=c99 -Wall -o demo demo.c

编译,当我运行它时,它会崩溃(非常可预测)。

为什么?数组参数中关键字的用途是static什么(顺便说一句,这个构造的名称是什么?)?

4

2 回答 2

15

static优化器有一个指示(一个提示——但不超过一个提示),它可能假设数组中至少有适当数量(在示例中为 5 个)元素(因此数组指针是也不为空)。这也是对使用函数的程序员的指令,他们必须将足够大的数组传递给函数以避免未定义的行为。

ISO/IEC 9899:2011

§6.7.6.2 数组声明器

约束
¶1 除了可选的类型限定符和关键字 之外static[and]可以分隔表达式或*. 如果它们分隔了一个表达式(它指定了一个数组的大小),则该表达式应为整数类型。如果表达式是常量表达式,它的值应大于零。元素类型不应是不完整类型或函数类型。可选类型限定符和关键字static应仅出现在具有数组类型的函数参数的声明中,然后仅出现在最外层的数组类型派生中。

§6.7.6.3 函数声明器(包括原型)

¶7 将参数声明为“类型数组”应调整为“类型限定指针”,其中类型限定符(如果有)是在数组类型派生的[and中指定的那些。]如果关键字static也出现在数组类型派生的[and]中,那么对于函数的每次调用,对应的实际参数的值应提供对数组的第一个元素的访问,该数组的元素至少与大小指定的一样多表达。


您的代码会崩溃,因为如果您将空指针传递给期望数组的函数(保证是 5 个元素的数组的开头)。您正在调用未定义的行为,并且崩溃是处理错误的一种非常明智的方式。

当您将一个包含 3 个整数的数组传递给一个保证包含 5 个整数的数组的函数时,它会更加微妙;再次,您调用未定义的行为,结果是不可预测的。崩溃相对不太可能;虚假结果的可能性很大。

实际上,static在这种情况下,the 有两个独立的工作——它定义了两个独立的合约:

  1. 它告诉函数的用户他们必须提供一个至少包含 5 个元素的数组(如果他们不这样做,他们将调用未定义的行为)。
  2. 它告诉优化器它可以假定一个指向至少 5 个元素的数组的非空指针,并且可以相应地进行优化。

如果函数的用户违反了函数的要求,所有的地狱都可能会崩溃(“鼻恶魔”等;通常是未定义的行为)。

于 2013-08-21T16:04:58.143 回答
1

您的代码是正确的(实际上建议...参见 C99,N1124/1256,第 6.7.5.3-7 条(参见下面乔纳森的全文):

如果关键字 static 也出现在数组类型派生的 [ 和 ] 中,则对于函数的每次调用,对应的实际参数的值应提供对至少与指定元素一样多的数组的第一个元素的访问由大小表达式。

错误在于您的数组定义-您将其分配为容纳 3 个元素,但随后您调用了一个需要五个元素的函数(通过[static 5]),从而触发了崩溃。

于 2013-08-21T16:10:58.270 回答