When declaring a function that accesses several consecutive values in memory, I usually use array arguments like
f(int a[4]);
It works fine for my purposes. However, I recently read the opinion of Linus Torvalds.
So I wonder if the array arguments are today considered obsolete? More particularly,
In any case, what about pointers to arrays?
void f(int (*a)[4]);
Note that this form is not prone to "sizeof" mistakes. But what about efficiency in this case? I know that GCC generates the same code (link). Is that always so? And what about further optimization opportunities in this case?
If you write
void f(int a[4]);
that has exactly the same meaning to the compiler as if you wrote
void f(int *a);
This is why Linus has the opinion that he does. The [4]
looks like it defines the expected size of the array, but it doesn't. Mismatches between what the code looks like it means and what it actually means are very bad when you're trying to maintain a large and complicated program.
(In general I advise people not to assume that Linus' opinions are correct. In this case I agree with him, but I wouldn't have put it so angrily.)
Since C99, there is a variation that does mean what it looks like it means:
void f(int a[static 4]);
That is, all callers of f
are required to supply a pointer to an array of at least four int
s; if they don't, the program has undefined behavior. This can help the optimizer, at least in principle (e.g. maybe it means the loop over a[i]
inside f
can be vectorized).
Your alternative construct
void f(int (*a)[4]);
gives the parameter a
a different type ('pointer to array of 4 int' rather than 'pointer to int'). The array-notation equivalent of this type is
void f(int a[][4]);
Written that way, it should be immediately clear that that declaration is appropriate when the argument to f
is a two-dimensional array whose inner size is 4, but not otherwise.
sizeof
issues are another can of worms; my recommendation is to avoid needing to use sizeof
on function arguments at almost any cost. Do not contort the parameter list of a function to make sizeof
come out "right" inside the function; that makes it harder to call the function correctly, and you probably call the function a lot more times than you implement it.