问题
There are 3 ways to pass arrays as function arguments.
- Formal parameters as a pointer, e.g.,
void myFunction(int *param) {}
- Formal parameters as a sized array, e.g.,
void myFunction(int param[10]) {}
- Formal parameters as an unsized array, e.g.,
void myFunction(int param[]) {}
Which way is better in terms of efficiency and readability?
回答1:
Which way is better to pass arrays as function arguments in C?
I am going for Door #4. The receiving function needs to know the size.
void myFunction(size_t array_element_count, int *param);
Alternatively code could use a terminating sentinel, but there are no special "I-am-not-an-int" values.
In terms of the below, they emit the same code. This is a style issue. As such, follow the group's style guide. For me I favor size_t array_element_count, int param[array_element_count]
as most informative to code's intent.
void myFunction(size_t array_element_count, int *param);
void myFunction(size_t array_element_count, int param[array_element_count]);
void myFunction(size_t array_element_count, int param[]);
In terms of style, f(size, ptr)
vs f(ptr, size)
, I recall reading on the next C rev promoting f(size, ptr)
. IAC, with more complex arrays and VLA support , the below is useful:
foo(size_t row, size_t col, matrix[row][col]);
回答2:
As far as the compiler is concerned, there is no difference.
Section 6.7.6.3p7 of the C standard regarding Function Declarators states:
A declaration of a parameter as ‘‘array oftype’’ shall be adjusted to ‘‘qualified pointer totype’’, where the type qualifiers (if any) are those specified within the
[
and]
of the array type derivation. If the keywordstatic
also appears within the[
and]
of the array type derivation, then for each call to the function, the value of the corresponding actual argument shall provide access to the first element of an array with at least as many elements as specified by the size expression.
So int *param
, int param[10]
, and int param[]
as functions parameters are exactly equivalent. The only difference is in terms of readability.
Generally, I would use the array syntax without the size if an array is expected so it's clearer to the reader what the parameter is for.
回答3:
All three notations are equivalent, which makes the sized array declaration very confusing:
With void myFunction(int param[10]);
you will not get strong type checking and sizeof(param)
will be the size of an int*
pointer, not that of the array passed to the function. Avoid this notation for these reasons.
C99 introduced a new syntax to specify that a pointer argument must point to an array of at least a certain number of items:
void myFunction(int param[static 10]);
This notation is not very common and compilers do not fully check the size constraint that it implies. Note also that sizeof(param)
is still that of a pointer. So part of the confusion remains.
For readability, I would suggest using void myFunction(int *param);
if param
points to an int
variable and void myFunction(int param[]);
if param
points to an array of int
. The size of this array should be passed as a separate argument.
With this convention, I usually define main
as:
int main(int argc, char *argv[]) { ... }
回答4:
If you know the size at compile time and can do it (e.g., because you aren't passing a pointer to a subarray), then I would say
struct ints10 { int ints10[10]; };
void myFunction(struct ints10 *param);
because that can be strongly type-checked and sizeof
will work on the destination as expected.
Otherwise
void myFunction(int param[10]);
void myFunction(int param[2]);
//doesn't matter that the sizing is inconsistent here
//the (innermost, e.g., if you have `int a[2][3][4]` in a param, it gets adjusted to `int (*a)[3][4]`) size is
//is adjusted to a pointer and isn't checked (comptime or runtime)
//for consistency only for positiveness (comptime)
void myFunction(int param[]);
void myFunction(int *param);
are all fully compatible as far as typechecking is concerned because of how array arguments are adjusted to pointers.
I would recommend being as descriptive as possible (i.e., int param[10]
) but keep in mind that the innermost index of an array specified as parameter is adjusted to a pointer, which means the size in it is only as good as a comment (except that the contents of it is syntactically checked and verified as a positive integer).
As far as codegeneration is concerned, all mentioned forms should generate the same assembly even on a not-very-smart compiler.
If you don't know the size at compile time, then you need an extra parameter for passing it, but passing it otherwise will make the function a tiny bit less efficient.
回答5:
In terms of a function parameter declaration, all three versions are treated exactly the same way.
Remember that under most circumstances1 array expressions "decay" to pointer expressions - that is, if you have something like
char arr[10];
foo( arr );
the expression arr
in the call to foo
"decays" from type "10-element array of char
" to "pointer to char
", so what foo
actually receives is an argument of type char *
:
void foo( char *a ) { ... }
As a "convenience", you may declare a
as char a[10]
or char a[]
, but they will be interpreted as char *a
.
- Except when it is the operand of the
sizeof
,_Alignof
, or unary&
operators, or is a string literal used to initialize a character array in a declaration, an expression of type "N-element array ofT
" will be converted ("decay") to an expression of type "pointer toT
and the value of the expression will be the address of the first element of the array.
来源:https://stackoverflow.com/questions/61777092/which-way-is-better-to-pass-arrays-as-function-arguments-in-c