Empty parameters list and function definition

F

Francis Moreau

Hello,

I read section 6.7.5.3p14 from C99 several times but it looks I missed
something in my understanding...

I put the revelant section for convenience:

An identifier list declares only the identifiers of the parameters
of the function. An empty
list in a function declarator that is part of a definition of that
function specifies that the
function has no parameters. The empty list in a function declarator
that is not part of a
definition of that function specifies that no information about the
number or types of the
parameters is supplied.

So to check that I understood correctly this, I wrote and tried to
compile the following code:

--- 8< ---

/*
* A function declaration with empty identifier list which is part of
* the definition specifies that the function has no parameters.
*/
int foo()
{
return 1;
}

/* A function declaration alone with empty list identifier specifies
* that no information about the number or types of the parameters is
* supplied.
*/
int bar();

void test(void)
{
foo(1); /* should fail */
bar(1); /* should be ok */
}

--- >8 ---

Gcc compiles this without any warnings (gcc -Wall -std=c99 -c func.c).
However I would expect gcc to issue an error or a warning since 'foo'
function takes no parameters (in my understanding).

Could anybody enlight me ?

Thanks
 
B

Ben Bacarisse

Francis Moreau said:
I read section 6.7.5.3p14 from C99 several times but it looks I missed
something in my understanding...

I put the revelant section for convenience:

An identifier list declares only the identifiers of the parameters
of the function. An empty
list in a function declarator that is part of a definition of that
function specifies that the
function has no parameters. The empty list in a function declarator
that is not part of a
definition of that function specifies that no information about the
number or types of the
parameters is supplied.

So to check that I understood correctly this, I wrote and tried to
compile the following code:

--- 8< ---

/*
* A function declaration with empty identifier list which is part of
* the definition specifies that the function has no parameters.
*/
int foo()
{
return 1;
}

/* A function declaration alone with empty list identifier specifies
* that no information about the number or types of the parameters is
* supplied.
*/
int bar();

void test(void)
{
foo(1); /* should fail */
bar(1); /* should be ok */
}

--- >8 ---

Gcc compiles this without any warnings (gcc -Wall -std=c99 -c func.c).
However I would expect gcc to issue an error or a warning since 'foo'
function takes no parameters (in my understanding).

That might be a good idea, but it does not have to. Calling a
function with the wrong parameter list is not a constraint violation
unless there is a prototype in scope. Add (void) to the function
definition and declaration and both will act as a prototype as well.
gcc will then warn you that they are being called incorrectly.

Add -Wstrict-prototypes and you will be told that neither the
definition of foo nor the declaration of bar acts as a prototype. I
always have this warning on since it lets me know that I have written
a function whose calls won't be checked.
 
F

Francis Moreau

That might be a good idea, but it does not have to.  Calling a
function with the wrong parameter list is not a constraint violation
unless there is a prototype in scope.

Ah ok, I thought it has to for definition case.
 Add (void) to the function
definition and declaration and both will act as a prototype as well.
gcc will then warn you that they are being called incorrectly.

Add -Wstrict-prototypes and you will be told that neither the
definition of foo nor the declaration of bar acts as a prototype.  I
always have this warning on since it lets me know that I have written
a function whose calls won't be checked.

I'll do the same.

Thanks you
 
F

Francis Moreau

     A definition is also a declaration, but the two roles are
not always in perfect lock-step.  `int foo() { return 1; }'
defines a function with no parameters, but as a declaration it
gives no information about the parameters.  (Almost none: we
know that foo has no "..." parameters, but that's all.)

Well still, reading 6.7.5.3p14:

"...An empty list in a function declarator that is part of a
definition of that function specifies that the function has no
parameters..."

it's still unclear if the function has no parameters for the
definition or as a declaration.
     This odd state of affairs may make just a little sense if
you think about the declaration you'd get by chopping off
foo's body and tacking on a semicolon: `int foo();'.  That
declaration gives (almost) no information about foo's parameters,
just like your declaration of bar.  That declaration, roughly
speaking, is the "external appearance" of foo; the additional
details are "private" to the definition itself.

ok I think I got your idea, but I'm still not sure this is equivalent
to 6.7.5.3p14.

But it's a good way to remember the rule.
     Recommendation: Don't write old-style function definitions
in new code, and rewrite old-style to new-style whenever you have
a good reason to visit a module containing them.  Note that it is
not always possible to write a portable prototype for an old-style
function: in `int barf(s) unsigned short s; { return s >> 3; }',
an `unsigned short' argument promotes to `int' on some platforms
and to `unsigned int' on others, so we don't know which to write
in a prototype.  Do a full change-over and all will be well.

Indeed.

Thanks
 
B

Ben Bacarisse

Francis Moreau said:
Well still, reading 6.7.5.3p14:

"...An empty list in a function declarator that is part of a
definition of that function specifies that the function has no
parameters..."

it's still unclear if the function has no parameters for the
definition or as a declaration.

I think Eric's words are a little confusing. Let me try to be clear.
There are four things to consider:

1. int foo() { return 1; }
2. int foo();
3. int foo(void) { return 1; }
4. int foo(void);

All four act as declarations of the function but only 1 and 3 are also
definitions. 3 and 4 also provide a prototype whereas 1 and 2 do not.

2 says the least. As a declarator with an empty parameter list that
is *not* part of a definition is says nothing about foo's parameters.

1, 3 and 4 all say that foo has no parameters but calls to foo with a
parameter will only be diagnosed in the case of 3 and 4. A compiler
is permitted to complain about foo(42) after seeing 1, but to do so it
need to distinguish between 1 and 2 because foo(42) is *not* wrong
after seeing only 2. I don't know a compiler that does this. For one
thing, it would involve a lot of effort being put into old-style
definitions.

<snip>
 

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

No members online now.

Forum statistics

Threads
473,763
Messages
2,569,562
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top