简体   繁体   English

我可以在C99中使用数组作为函数参数吗?

[英]Can I use arrays as a function parameter in C99?

The C99 standard says the following in 6.7.5.3/7: C99标准在6.7.5.3/7中指出以下内容:

A declaration of a parameter as ''array of type'' shall be adjusted to ''qualified pointer to type'', where the type qualifiers (if any) are those specified within the [ and ] of the array type derivation. 参数声明为“类型数组”应调整为“类型的合格指针”,其中类型限定符(如果有)是在数组类型派生的[和]中指定的那些。

Which I understand as: 我的理解为:

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

However, gcc 4.7.3 will happily accept both function definitions, even when compiled with gcc -Wall -Werror -std=c99 -pedantic-errors . 但是,即使使用gcc -Wall -Werror -std=c99 -pedantic-errors编译,gcc 4.7.3也会很乐意接受这两个函数定义。 Since I am not a C expert, I am unsure if maybe I misinterpreted what the standard is saying. 由于我不是C专家,所以我不确定是否可能误解了标准所说的内容。

I also noticed that 我也注意到

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

will always return sizeof(int *) instead of the array size, which firms my belief that int arr[] is handled as int * and gcc is just trying to make me feel more comfortable. 将始终返回sizeof(int *)而不是数组大小,这坚定了我的信念,即将int arr[]处理为int *而gcc只是想让我感到更舒服。

Can someone shed some light on this issue? 有人可以阐明这个问题吗? Just for reference, this question arose from this comment . 仅供参考,此问题来自此评论

Some context: 一些背景:

First of all, remember that when an expression of type "N-element array of T " appears in a context where it isn't the operand of the sizeof or unary & operator, or isn't a string literal being used to initialize another array in a declaration, it will be converted to an expression of type "pointer to T " and its value will be the address of the first element in the array. 首先,请记住,当“ N的T N个元素的数组”类型的表达式出现在不是sizeof或一元&运算符的操作数或者不是用于初始化另一个的字符串文字的上下文中时,数组在声明中,它将被转换为“ pointer to T ”类型的表达式,其值将为数组中第一个元素的地址。

That means when you pass an array argument to a function, the function will receive a pointer value as a parameter; 这意味着当您将数组参数传递给函数时,该函数将收到一个指针值作为参数。 the array expression is converted to a pointer type before the function is called. 在调用函数之前,将数组表达式转换为指针类型。

That's all well and good, but why is arr[] allowed as a pointer declaration? 一切都很好,但是为什么允许arr[]作为指针声明? I can't say that this is the reason for sure , but I suspect it's a holdover from the B language, from which C was derived. 我不能说这是确定的原因,但是我怀疑这是从B语言继承而来的,C语言是从C语言派生而来的。 In fact, pretty much everything hinky or unintuitive about arrays in C is a holdover from B. 实际上,关于C中数组的所有棘手或不直观的事情几乎都是B的保留。

B was a "typeless" language; B是一种“无类型”语言; you didn't have different types for floats, integers, text, whatever. 您没有不同的浮点,整数,文本类型。 Everything was stored as fixed-size words, or "cells", and memory was treated as a linear array of cells. 一切都存储为固定大小的单词或“单元”,而内存被视为单元的线性阵列。 When you declared an array in B, as in 当您在B中声明数组时,如

auto arr[10];

the compiler would set aside 10 cells for the array, and then set aside an additional 11th cell that would store an offset to the first element of the array, and that additional cell would be bound to the variable arr . 编译器将为该数组留出10个单元格,然后留出一个额外的第11个单元格,该单元格将存储到数组第一个元素的偏移量,并且该额外的单元格将绑定到变量arr As in C, array indexing in B was computed as *(arr + i) ; 与C中一样,B中的数组索引计算为*(arr + i) you'd take the value stored in arr , add an offset i , and dereference the result. 您将使用存储在arr的值,添加一个偏移量i ,然后取消对结果的引用。 Ritchie retained most of these semantics, with the huge exception of no longer setting aside storage for the pointer to the first element of the array; Ritchie保留了大多数这些语义,但有一个很大的例外,那就是不再为指针的第一个元素留出存储空间。 instead, that pointer value would be computed from the array expression itself when the code was translated. 而是在翻译代码时从数组表达式本身计算该指针值。 This is why array expressions are converted to pointer types, why &arr and arr give the same value, if different types (the address of the array and the address of the first element of the array are the same) and why an array expression cannot be the target of an assignment (there's nothing to assign to ; no storage has been set aside for a variable independent of the array elements). 这就是为什么将数组表达式转换为指针类型的原因,为什么&arrarr给出相同的值,如果类型不同(数组的地址和数组的第一个元素的地址相同),以及为什么数组表达式不能为分配的目标(没有要分配的内容 ;没有为独立于数组元素的变量预留存储空间)。

Now here's the fun bit; 现在这是有趣的一点; in B, you'd declare a "pointer" as 在B中,您需要声明“指针”为

auto ptr[];

This had the effect of allocating the cell to store the offset to the first element of the array and binding it to ptr , but ptr didn't point anywhere in particular; 这具有分配单元以将偏移量存储到数组的第一个元素并将其绑定到ptr ,但是ptr并没有特别指出。 you could assign it to point to various locations. 您可以将其分配为指向各个位置。 I suspect that notation was held over for a couple of reasons: 我怀疑这种记号被保留有两个原因:

  1. Most of the guys who worked on the initial version of C were familiar with it; 从事C初始版本工作的大多数人都熟悉它。
  2. It sort of emphasizes that the parameter represents an array in the caller; 它强调了参数代表调用者中的数组。

Personally, I would have preferred that Ritchie had used * to designate pointers everywhere, but he didn't (or, alternately, use [] to designate a pointer in all contexts, not just a function parameter declaration). 就个人而言,我本来希望Ritchie使用*来在任何地方指定指针,但他没有(或者,可以使用[]在所有上下文中指定指针,而不仅仅是函数参数声明)。 I will normally recommend that everyone use * notation for function parameters instead of [] , simply because it more accurately conveys the type of the parameter, but I can understand why people would prefer the second notation. 我通常会建议每个人都对函数参数使用*表示法,而不是[] ,只是因为它可以更准确地传达参数的类型,但是我可以理解为什么人们会喜欢第二种表示法。

Both your valid and invalid declarations are internally equivalent, ie, the compiler converts the latter to the former. 有效声明和无效声明在内部都是等效的,即,编译器将后者转换为前者。

What your function sees is the pointer to the first element of the array. 您的函数看到的是指向数组第一个元素的指针。

PS. PS。 The alternative would be to push the whole array on the stack, which would be grossly inefficient from both time and space viewpoints. 另一种选择是将整个阵列压入堆栈,从时间和空间角度来看,这都是非常低效的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM