Does the C function call additional arguments?

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 a function to be called with more parameters than it takes?

I assume it is completely ABI dependent and how it determines where both function arguments and local variables are stored. Moreover, it is most likely not portable code. But I've seen this idiom used multiple times in real-world code.

+2


source to share


1 answer


As a practical matter, I don't know how "portable" it is (in the sense of whether it will behave as you expected within existing implementations, or at least under a subset of implementations you are worried about).

As for the C standard, it is not portable at all. Your program has undefined behavior because it calls a function via an expression like ( int(*)(int, int)

which is different from the actual type of the function ( int(*)(int, int, int)

). (The first type used to define yours add

, the last is the type of expression fn

used as a call prefix.)

This is stated in "C" Section 6.5.2.2 Clause 9:

If the function is defined with a type that is incompatible with the type (of the expression) pointed to by the expression that denotes the behavior is called undefined.

(Link to the PDF of draft N1570 of the C11 standard. You will find similar or possibly identical wording in other editions of the standard.)



My advice: don't do this.

Note, however, that extra arguments for variational functions (functions of type printf()

declared with , ...

) are 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 work (although you will lose compilation type checking for any arguments that match , ...

).

For nonvariant functions, you can freely convert function pointers from one type to another, but you need to convert back to the correct type for each call.

+7


source







All Articles