Reputation: 3083
Consider the following code:
#include <stdio.h>
typedef int (*addif_fn_t) (int, int, int);
int add (int a, int b) {
return a + b;
}
int addif (int a, int b, int cond) {
return cond ? (a + b) : 0;
}
int main() {
addif_fn_t fn;
fn = addif;
printf("addif:\t%d %d\n", fn(1, 2, 1), fn(1, 2, 0));
fn = (addif_fn_t)add;
printf("add:\t%d %d\n", fn(1, 2, 1), fn(1, 2, 0));
return 0;
}
On any Intel machine using the standard C calling convention, this results in:
addif: 3 0
add: 3 3
The question is: how portable is this idiom? Does C allow calling a function with more parameters than it accepts?
My guess is that it depends entirely upon the ABI and how it determines out where both the function arguments and local variables are stored. More to the point, this is likely not portable code. But I have seen this idiom used several times in real codebases.
Upvotes: 4
Views: 321
Reputation: 263497
As a practical matter, I don't know how "portable" it is (in the sense of whether it will behave as you expected to under existing implementations, or at least under the subset of implementations you're concerned about).
As far as the C standard is concerned, it's not portable at all. Your program has undefined behavior, because it calls a function via an expression of a type (int(*)(int, int)
that differs from the actual type of the function (int(*)(int, int, int)
). (The former is the type used to define your add
function; the latter is the type of the expression fn
used as the prefix of the call.)
This is stated in the C standard, section 6.5.2.2 paragraph 9:
If the function is defined with a type that is not compatible with the type (of the expression) pointed to by the expression that denotes the called function, the behavior is undefined.
(The link is to a PDF of the N1570 draft of the C11 standard. You'll find similar, or probably identical, wording in other editions of the standard.)
My advice: Don't Do That.
Note, however, that excess arguments to variadic functions (functions like printf()
that are declared with a , ...
) are quietly ignored. For example, this is perfectly legal:
printf("Ignore the arguments\n", 10, 20, 30);
If you really need to be able to call a function without knowing how many arguments it expects, this might be a workable approach (though you'll lose compile-time type checking for any arguments matching the , ...
).
For non-variadic functions, you can freely convert function pointers from one type to another, but you have to convert back to the correct type for each call.
Upvotes: 7