What are the semantics of function pointers with empty parentheses in each C standard?

佐手、 提交于 2021-01-28 08:22:28

问题


Answers to this and this question say that function pointers of the form return-type (*pointer)() are pointers to a function which takes any number of arguments, though the latter says they obsolesced in C11.

On an i386 system with GCC, “extra” arguments passed in a call to an empty-parentheses-type’d function pointer are ignored, because of how stack frames work; e.g.,

/* test.c */
#include <stdio.h>

int foo(int arg) { return arg; }

int main(void)
{
    int (*fp)() = foo;
    printf("%d\n", fp(267239151, 42, (struct { int x, y, z; }){ 1, 2, 3 }));
    return 0;
}

$ gcc -o test test.c && ./test
267239151
$ 

In which C standards are empty-parentheses’d function pointers allowed? and wherever so, what are they specified to mean?


回答1:


N1570 6.11.6:

The use of function declarators with empty parentheses (not prototype-format parameter type declarators) is an obsolescent feature.

This same wording appears in the 1990, 1999, and 2011 editions of the ISO C standard. There has been no change. The word obsolescent says that the feature may be removed in a future edition of the Standard, but so far the committee has not done so. (Function pointer declarations are just one of several contexts where function declarators can appear.)

The Introduction section of the C standard explains what obsolescent means:

Certain features are obsolescent, which means that they may be considered for withdrawal in future revisions of this International Standard. They are retained because of their widespread use, but their use in new implementations (for implementation features) or new programs (for language [6.11] or library features [7.31]) is discouraged.

A call to a function declared with an old-style declarator is still required to pass the correct number and type(s) of arguments (after promotion) as defined by the function's actual definition. A call with incorrect arguments has undefined behavior, which means that the compiler is not required to diagnose the error; the burden is entirely on the programmer.

This is why prototypes were introduced, so that the compiler could check correctness of arguments.

On an i386 system with GCC, “extra” arguments passed in a call to an empty-parentheses-type’d function pointer are ignored, because of how stack frames work ...

Yes, that's well within the bounds of undefined behavior. The worst symptom of undefined behavior is having the program work exactly as you expect it to. It means that you have a bug that hasn't exhibited itself yet, and it will be difficult to track it down.

You should not depend on that unless you have a very good reason to do so.

If you change

int (*fp)() = foo;

to

int (*fp)(int) = foo;

the compiler will diagnose the incorrect call.




回答2:


Any function declarator can have empty parentheses (unless it's a function declaration where there is already a non-void prototype in scope). This isn't deprecated, although it is "obsolescent".

In a function pointer, it means the pointer can point to a function with any argument list.

Note that when actually calling a function through the pointer, the arguments must be of correct type and number according to the function definition, otherwise the behaviour is undefined.




回答3:


Although C allows you to declare a function (or pointer to function) with an empty parameter list, that does not change the fact that the function must be defined with a precise of parameters, each with a precise type. [Note 1]

If the parameter declaration is not visible at a call site, the compiler will obviously not be able to perform appropriate conversions to the provided arguments. It is, therefore, the programmer's responsibility to ensure that there are a correct number of arguments, all of them with the correct type. For some parameter types, this will not be possible because the compiler will apply the default argument promotions. [Note 2]

Calling a function with an incorrect number of arguments or with an argument whose type is not compatible with the corresponding parameter type is Undefined Behaviour.

The fact that the visible declaration has an empty parameter list does not change the way the function is called. It just puts more burden on the programmer to ensure that the call is well-defined.

This is equally true of pointer to function declarations.

In short, the sample code in the question is Undefined Behaviour. It happens to "work" on certain platforms, but it is neither portable nor is it guaranteed to keep working if you recompile. So the only possible advice is "Don't do that."

If you want to create a function which can accept extra arguments, use a varargs declaration. (See open for an example.) But be aware of the limitations: the called function must have some way of knowing the precise number and types of the provided arguments.


Notes

  1. With the the exception of varargs functions, whose prototypes end with .... But a declaration with an empty parameter list cannot be used to call a varargs function.

  2. Integer types narrower than int are converted to int and float values to double.



来源:https://stackoverflow.com/questions/49472831/what-are-the-semantics-of-function-pointers-with-empty-parentheses-in-each-c-sta

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!