2013-09-16 69 views
0

C99标准说,在6.7.5.3/7以下:我可以在C99中使用数组作为函数参数吗?

一个参数作为“”“类型的数组”的声明,应调整至“”合格指针 类型“”,其中类型限定符(如果有)是在数组类型派生的[和]中指定的那些。

我的理解是:

void foo(int * arr) {} // valid 
void foo(int arr[]) {} // invalid 

然而,GCC 4.7.3会很乐意接受这两个函数定义,即使与gcc -Wall -Werror -std=c99 -pedantic-errors编译。由于我不是C专家,我不确定我是否可能误解了标准的内容。

我也注意到,

size_t foo(int arr[]) { return sizeof(arr); } 

总是返回的sizeof(int *)代替数组大小,这公司我相信int arr[]作为int *处理和gcc只是试图让我感觉更舒服。

有人可以解释一下这个问题吗?仅供参考,此问题源自this comment

+2

编译器正在执行C99 std引用的说法:它将'[]'形式调整为'*'形式。因此这两者是等同的。几乎没有办法将整个数组按值传递给C函数。您只能传递一个指针并在函数体内手动创建副本。例外情况是,记录中的数组字段将在按值传递时与记录一起传递。因此,您有时会看到一个数组字段的记录,其中记录仅仅是包装数组以获得此效果。 – Gene

+0

@Gene D'uh,我犯了一个错误,把这个标准的段落作为对C程序员的指令,而不是C编译器。愚蠢的我。 – nijansen

回答

2

无论您有效无效声明是内部等价的,即编译器将后者到前者。

你的函数看到的是指向数组的第一个元素的指针。

PS。另一种方法是将整个阵列推向堆栈,从时间和空间的角度来看,这将是非常低效的。

3

一些上下文:

首先,请记住,当它是不sizeof或一元&操作者的操作数,或类型“的T N元件阵列”的表达出现在上下文不是用于在声明中初始化另一个数组的字符串文本,它将被转换为类型为“指向T的指针”的表达式,其值将是数组中第一个元素的地址。

这意味着当您将一个数组参数传递给一个函数时,该函数将接收一个指针值作为参数;在函数被调用之前,数组表达式被转换为指针类型。

这一切都很好,但为什么arr[]允许作为指针声明?我不能说这就是肯定是的原因,但我怀疑它是从C语言衍生的B语言中保留下来的。事实上,几乎所有关于C中的数组的东西都是狡猾的或不直观的,这是从B的缓冲中获得的。

B是一种“无类型”语言;你没有为浮动,整数,文本,不管什么类型。一切都以固定大小的单词或“单元格”存储,而内存被视为一个线性单元格阵列。当你在

auto arr[10]; 

宣告乙一个阵列,编译器会搁置10细胞阵列,然后搁置,将存储的偏移到所述阵列的所述第一元件的额外11细胞,并额外的单元格将被绑定到变量arr。与C中一样,B中的数组索引计算为*(arr + i);你会将存储在arr中的值,添加一个偏移量i,并取消引用结果。里奇保留了大部分这些语义,除了不再为数组的第一个元素指定存储空间外,相反,当代码被翻译时,该指针值将是,从数组表达式本身计算。这就是为什么数组表达式转换为指针类型的原因,为什么&arrarr给出相同的值,如果不同的类型(数组的地址和数组的第一个元素的地址相同)以及为什么数组表达式不能分配的目标(没有什么可以将分配给;没有存储空间用于独立于数组元素的变量)。

现在,这里是有趣的一点;在B,你会申报了“指针”作为

auto ptr[]; 

这不得不分配单元存储的偏移量数组的第一个元素,并将其绑定到ptr的效果,但ptr没点特别是任何地方;你可以指定它指向不同的位置。我怀疑这个符号是因为几个原因而被搁置的:

  1. 大部分在C初始版本上工作的人都熟悉它;
  2. 它强调参数代表调用者中的一个数组;

就个人而言,我更希望里奇曾使用*到处指定三分球,但他没有(或交替使用[]在所有情况指定一个指针,而不仅仅是一个函数参数声明)。我通常会建议每个人都使用*表示法来表示函数参数,而不是[],因为它更准确地表达了参数的类型,但我可以理解为什么人们更喜欢第二种表示法。

相关问题