开发者

Functions of varying arity called through pointers to functions of unspecified arguments

I'm 99% convinced that this is legitimate after reviewing the C standard and several comp.lang.c posts, but am hoping that someone can provide the precise language in the standard that allows (or forbids) this case:

#include <stdio.h>

double id (double x) { return x; }
double add2 (double x, double y) { return x + y; }
double add3 (double x, double y, double z) { return x + y + z; }

typedef double (*fp) ();
static fp funcs[] = { id, add2, add3 };

int main (void)
{
    printf("id(5.3) = %f\n", funcs[0](5.3));
    printf("add2(5.3, 6.1) = %f\n", funcs[1](5.3, 6.1));
    printf("add3(5.3, 6.1, 7.2) = %f\n", funcs[2](5.3, 6.1, 7.2));

    return 0;
}

The provided example gave the expected results for me under MinGW gcc 4.4.0 using -Wall -pedantic -ansi.

Considerations:

  • I'm aware that calls to functions with unspecified parameters implicitly promote integral arguments according to the integral开发者_运维技巧 promotion rules and float arguments to double. Does this behavior change in any way when calling through a function pointer to a function of unspecified parameters? (I don't see why it would.)
  • I came across several posts implying that calls to functions with ... specifiers (e.g. double uhoh (double x, ...)) are not permitted through function pointers to functions of unspecified parameters. This makes sense from an implementation perspective, but I haven't been able to pin down the clause in the standard which forbids this.


First I can suggest that the standard function call syntax:

void foo(int);
foo(3);

is defined in terms of foo decaying to a function pointer, then being invoked; therefore I don't see why there would be any difference between your situation and a "standard" function call.

Second, n1256 6.5.2.2 details function call semantics, and it seems pretty well-defined for a function pointer with no prototype provided the number and type of arguments matches the number and type of parameters.

An empty parameter list is incompatible with a variadic parameter list according to n1256 6.7.5.3p15:

If one type has a parameter type list and the other type is specified by a function declarator that is not part of a function definition and that contains an empty identifier list, the parameter list shall not have an ellipsis terminator and the type of each parameter shall be compatible with the type that results from the application of the default argument promotions.

This means it is a constraint violation (6.5.16.1p1) to assign a variadic function pointer to a pointer-to-function with no prototype, since you are assigning pointers to incompatible types.

I would guess that casting a variadic function pointer to a non-prototyped function pointer is also UB and possibly a CV; but I haven't checked.


You are correct that this program has entirely well-defined behavior as long as the arguments when you make the call are of the number and types matching those in the definition of the function that gets called. See 6.5.2.2 paragraph 6. My related question may also be of interest:

Is this dubious use of a non-prototype function declaration valid?


The code is well-defined as long as all parameter types promote to themselves and all supplied argument are of correct type.

If you want to get back some measure of type-safety, you could use explicit casts or unions, eg

#include <stdio.h>

static double id(double x) { return x; }
static double add2(double x, double y) { return x + y; }
static double add3(double x, double y, double z) { return x + y + z; }

union func
{
    double (*as_unary)(double x);
    double (*as_binary)(double x, double y);
    double (*as_ternary)(double x, double y, double z);
};

static const union func funcs[] = {
    { .as_unary = id },
    { .as_binary = add2 },
    { .as_ternary = add3 }
};

int main(void)
{
    printf("id(5.3) = %f\n", funcs[0].as_unary(5.3));
    printf("add2(5.3, 6.1) = %f\n", funcs[1].as_binary(5.3, 6.1));
    printf("add3(5.3, 6.1, 7.2) = %f\n", funcs[2].as_ternary(5.3, 6.1, 7.2));

    return 0;
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜