Empty function parameter list

M

Maxim Fomin

I have a question related to empty function parameter list: is it
legal to call function with specific arguments via function pointer to
same type with empty parameter list?

Test example is:

#include <stdio.h>

int (*funcptr)();

int foo(int x)
{
return x;
}

int main()
{
funcptr = foo;
printf("%d\n", funcptr(7));
return 0;
}

Compiler that I use issues warning for funcptr definition ("function
declaration isn’t a prototype") but not for call.

n1570 says in 6.7.6.3-3 that an identifier list in a function
declaration which is not a definition should be empty - as far I
understand the statement, it surprisingly forbids features like void
func(int x);

In.14 it says that empty list for function definition means that the
function has no arguments. I understand that for ex. int main(){...}
and int main(void){...} are the same.

But later it says that code void func(){...} is legal and that is
provides no information about arguments. It also says that this is an
"obsolete" way.

So, I found it unclear:
1) whether each function (non-definition) declaration parameter list
should be empty
2) whether void func(void) and void func() are equal
3) related to what is described code obsolete
4) (most important) are function calls via pointers to function with
empty parameter list with some arguments valid (assuming as in the
example that pointer points to proper function)

Thanks in advance.
 
E

Eric Sosman

I have a question related to empty function parameter list: is it
legal to call function with specific arguments via function pointer to
same type with empty parameter list?

The function pointer used at the call site must be compatible
with the actual type of the called function, or the behavior is
undefined (6.5.2.2p9).
Test example is:

#include <stdio.h>

int (*funcptr)();

int foo(int x)
{
return x;
}

int main()
{
funcptr = foo;

I expected a diagnostic here because the parameter lists `()'
and `(int x)' are different, making the types of `funcptr' and
`foo' different. But "different" and "incompatible" are not quite
the same, and I'm not 100% sure about whether this assignment is
legal or not. Let's leave it to the language lawyers, okay?
printf("%d\n", funcptr(7));
return 0;
}

Compiler that I use issues warning for funcptr definition ("function
declaration isn’t a prototype") but not for call.

There's nothing wrong with the call itself: If `funcptr' points
to a suitable target function, everything is fine. My only question
is whether `foo' is a suitable target.
n1570 says in 6.7.6.3-3 that an identifier list in a function
declaration which is not a definition should be empty - as far I
understand the statement, it surprisingly forbids features like void
func(int x);

It's not forbidden -- but it's not an "identifier-list" either.
The "identifier-list" is a group of typeless parameter names as
used in an K&R-style function definition:

void func(x) // "identifier-list" between parentheses
int x;
{
printf("%d\n", x);
}
In.14 it says that empty list for function definition means that the
function has no arguments. I understand that for ex. int main(){...}
and int main(void){...} are the same.

But later it says that code void func(){...} is legal and that is
provides no information about arguments. It also says that this is an
"obsolete" way.

The "no information" language applies to

"a function declarator that is not part of a definition"

So your example is not quite right: `void func() {...}' defines
a function of no arguments, but `void func();' (no function body)
is not a definition: It is a declaration, and it says nothing about
the parameters (except that you can infer they don't end `...').
So, I found it unclear:
1) whether each function (non-definition) declaration parameter list
should be empty

I'm not sure what your confusion is on this point.
2) whether void func(void) and void func() are equal

They are equivalent in function *definitions* (followed by a
statement block that is the function body), but inequivalent as
*declarations* (no statements).
3) related to what is described code obsolete

K&R-style function definitions and declarations are obsolescent.
4) (most important) are function calls via pointers to function with
empty parameter list with some arguments valid (assuming as in the
example that pointer points to proper function)

I used to think "No" (and still think "No" for some cases), but
I'm not 100% sure what you've done is wrong. Poor practice, though.
 
J

James Kuyper

I have a question related to empty function parameter list: is it
legal to call function with specific arguments via function pointer to
same type with empty parameter list?

Test example is:

#include <stdio.h>

int (*funcptr)();

int foo(int x)
{
return x;
}

int main()
{
funcptr = foo;
printf("%d\n", funcptr(7));
return 0;
}

Compiler that I use issues warning for funcptr definition ("function
declaration isn’t a prototype") but not for call.

n1570 says in 6.7.6.3-3 that an identifier list in a function
declaration which is not a definition should be empty - as far I
understand the statement, it surprisingly forbids features like void
func(int x);

No, "int x" is an example of a parameter-type-list (6.7.6p1).
An identifier-list is something different that is part of the old K&R
style function definition syntax, which is still supported by the C
standard. It has nothing to do with function prototypes. An old style
function definition looks like this:

int func(x /* identifier list */)
int x; /* declaration list */
{
return x;
}

What 6.7.6.3-3 is saying is that identifier lists can only occur in
function definitions, not in function declarations that are not definitions:

int func(x); /* CONSTRAINT VIOLATION */
int func(); /* Permitted, but obsolescent */
int func(int x); /* Preferred. */
In.14 it says that empty list for function definition means that the
function has no arguments. I understand that for ex. int main(){...}
and int main(void){...} are the same.

It's actually been argued that they are not. Whether or not they're they
same matters only if there are recursive calls to main() farther down in
the same translation unit. But that gets into tricky issues that most
people don't have to worry about.
But later it says that code void func(){...} is legal and that is
provides no information about arguments. It also says that this is an
"obsolete" way.

Yes. The identifier-list of an old-style function declaration is
optional; the parameter-type-list of a modern function prototype is not,
so if there's nothing between the '(' and the ')', it's an old-style
function declaration with no identifier-list.
So, I found it unclear:
1) whether each function (non-definition) declaration parameter list
should be empty

You should use function prototype declarations, with a non-empty
parameter-list; use 'void' if there are no arguments.
You should not use old-style function declarations. However, if you
choose to do so, their identifier lists must be empty.
2) whether void func(void) and void func() are equal

In function definitions, they both specify that the function takes no
parameters. However, in function declarations that are not function
definitions, they are significantly different:

void func1(void);
void func2();
void (*pfunc)(int x);
int x;
func1(x); // Constraint violation
func2(x); // Undefined behavior
pfunc=func1; // Constraint violation
pfunc = func2; // Permitted
pfunc(x); // Undefined behavior
*(void(*)())pfunc)(x); // Safe
3) related to what is described code obsolete

Old style function definitions and declarations.
4) (most important) are function calls via pointers to function with
empty parameter list with some arguments valid (assuming as in the
example that pointer points to proper function)

If the number of arguments doesn't match the number of parameters in the
function definition, the behavior is undefined. The difference is that
with function prototypes, attempting to do this is a constraint
violation, which is required to produce a diagnostic message, and is
likely to prevent your program from being compiled. With the old style
declarations, it's undefined behavior, and your compiler will probably
not be able to detect that fact if the function declaration and the
function definition are in different modules. You'll find out only at
run time, an only if the malfunctioning code malfunctions in a
sufficiently obvious way for you to notice.
 
J

James Kuyper

On 6/13/2012 5:48 PM, Maxim Fomin wrote: ....

I expected a diagnostic here because the parameter lists `()'
and `(int x)' are different, making the types of `funcptr' and
`foo' different. But "different" and "incompatible" are not quite
the same, and I'm not 100% sure about whether this assignment is
legal or not. Let's leave it to the language lawyers, okay?

I answered the rest of his message, but missed his original question.

A function type with an unspecified number of arguments is compatible
with one that has a parameter type list, which is why that is not a
constraint violation. The requirement in 6.7.6.3p15, that both function
types must have matching parameter lists, only applies "if both are
present". If either parameter list is not present, then the parameter
list that is present doesn't interfere with compatibility.
 
D

Dinesh Kalal

I have a question related to empty function parameter list: is it
legal to call function with specific arguments via function pointer to
same type with empty parameter list?

Test example is:

#include <stdio.h>

int (*funcptr)();

int foo(int x)


void fucn() and func(void) are diffrent as we say: void func() means func retuns nothing.
 
M

Maxim Fomin

четверг, 14 Ð¸ÑŽÐ½Ñ 2012 г., 2:50:13 UTC+4 пользователь James Kuyper напиÑал:
I answered the rest of his message, but missed his original question.

A function type with an unspecified number of arguments is compatible
with one that has a parameter type list, which is why that is not a
constraint violation. The requirement in 6.7.6.3p15, that both function
types must have matching parameter lists, only applies "if both are
present". If either parameter list is not present, then the parameter
list that is present doesn't interfere with compatibility.

So, if int foo() and int foo(int x) are compatible, than assigning pointer to the second function to the variable which is pointer to the the first one (and subsequent call with integer argument) should not cause UB?

AFAIK for a function to be called properly it is required that called function should be supplied with right types of arguments in right sequence. However, it is not directly specified what should happen in the case of original example.
 
B

Ben Bacarisse

Maxim Fomin said:
четверг, 14 Ð¸ÑŽÐ½Ñ 2012 г., 2:50:13 UTC+4 пользователь James Kuyper напиÑал:

So, if int foo() and int foo(int x) are compatible, than assigning
pointer to the second function to the variable which is pointer to the
the first one (and subsequent call with integer argument) should not
cause UB?

Yes. The pointer types are compatible so the assignment is OK and no
diagnostic is required. The subsequent call (funcptr(7)) passes the
correct number and type of arguments to the called function, so that's
OK too.
AFAIK for a function to be called properly it is required that called
function should be supplied with right types of arguments in right
sequence. However, it is not directly specified what should happen in
the case of original example.

I am not sure why you say this. The original example called the
function (foo) with the correct number and type of argument so it is
fine.
 
J

James Kuyper

void fucn() and func(void) are diffrent as we say: void func() means func retuns nothing.


True (except for several typos). Relevant? The text you quote doesn't
reference void in any way.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top