Last named parameter not function or array? Last named parameter not function or array? arrays arrays

Last named parameter not function or array?


The restriction against register parameters or function parameters are probably something like:

  • you are not allowed to take the address of a variable with the register storage class.
  • function pointers are sometimes quite different than pointers to objects. For example, they might be larger than pointers to objects (you can't reliably convert a function pointer to an object pointer and back again), so adding some fixed number to the address of a function pointer might not get you to the next parameter. If va_start() and/or va_arg() were implemented by adding some fixed amount to the address of paramN and function pointers were larger than object pointers the calculation would end up with the wrong address for the object va_arg() returns. This might not seem to be a great way to implement these macros, but there might be platforms that have (or even need) this type of implementation.

I can't think of what the problem would be to prevent allowing array parameters, but PJ Plauger says this in his book "The Standard C Library":

Some of the restrictions imposed on the macros defined in <stdarg.h> seem unnecessarily severe. For some implementations, they are. Each was introduced, however, to meet the needs of at least one serious C implementation.

And I imagine that there are few people who know more about the ins and outs of the C library than Plauger. I hope someone can answer this specific question with an actual example; I think it would be an interesting bit of trivia.

New info:


The "Rationale for International Standard - Programming Languages - C" says this about va_start():

The parmN argument to va_start was intended to be an aid to implementors writing the definition of a conforming va_start macro entirely in C, even using pre-C89 compilers (for example, by taking the address of the parameter). The restrictions on the declaration of the parmN parameter follow from the intent to allow this kind of implementation, as applying the & operator to a parameter name might not produce the intended result if the parameter’s declaration did not meet these restrictions.

Not that that helps me with the restriction on array parameters.


It's not undefined. Keep in mind that when parameter is declared as int paramN[], the actual parameter type will still decay to int* paramN immediately (which is visible in C++, for example, if you apply typeid to paramN).

I must admit that I'm not sure what this bit in the spec is even for, considering that you cannot have parameters of function or array types in the first place (since they will pointer-decay).


I found another relevant quote, from Dinkumware.

The last parameter must not have register storage class, and it must have a type that is not changed by the translator. It cannot have:

* an array type* a function type* type float* any integer type that changes when promoted* a reference type [C++ only]

So apparently, the problem is precisely that the parameter gets passed in a way different from how it is declared. Interestingly enough, they also ban float and short, even though those should be supported by the standard.

As a hypothesis, it could be that some compilers have problems doing sizeof correctly on such parameters. E.g. it might be that, for

int f(int x[10]){        return sizeof(x);}

some (buggy) compiler will return 10*sizeof(int), thus breaking the va_start implementation.