what does this warning mean ?

  • Thread starter Heinrich Pumpernickel
  • Start date
B

Ben Bacarisse

jacob navia said:
This is the definition of a function with an unspecified
number of arguments.

You may have missed it because it is in the "wrong" place, but:

6.7.5.3 Function declarators (including prototypes)

states in paragraph 14:

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.
I do not think so. But I am not a language lawyer.

Is it not an important skill for a compiler writer?
This means that main has no prototype since you did NOT
provide a prototype

Here I am with you.

6.9.1 Function definitions

states in paragraph 7:

The declarator in a function definition specifies the name of the
function being defined and the identifiers of its parameters. If the
declarator includes a parameter type list, the list also specifies
the types of all the parameters; such a declarator also serves as a
function prototype for later calls to the same function in the same
translation unit. If the declarator includes an identifier list,139)
the types of the parameters shall be declared in a following
declaration list. In either case, the type of each parameter is
adjusted as described in 6.7.5.3 for a parameter type list; the
resulting type shall be an object type.

This suggests to me that a function definition with no "parameter tpye
list" (note that int main() has an empty "identifier list" -- no the
same at all) is not a prototype. Given the special execption I quote
above it seems likely that this is a bug in the standard, but there it
is. I think you are right that int main() does not act as a prototype
for subsequent calls.
and main *IS* always called!

Ah, but that is not the meaning of "for later calls to the same
function in the translation unit". You would be right to complain
about:

int main()
{
return main();
}

because the subsequent call has no prototype.

It is an ANSI definition. int main(void) is OK but so are equivalent
forms and they snuck in a phrase that makes int main() equivalent. At
least that is my reading of it.
 
R

Richard Bos

jacob navia said:
Under the highest warning level, a compiler should warn
about

int main()

since it is an obsolete syntax.

No, it isn't. It is obsolescent as a declaration. One may argue whether
it is obsolescent as the header of a _definition_ (you should really
know the difference) as well, but one cannot seriously argue that it is
already obsol_ete_, which is a rather stronger category than
obsol_escent_.
Note that lcc-win does NOT warn in the default warning level.

So to avoid this bug in your software we have to avoid getting a strong
level of error checking. Nice. Sounds like Microsoft-quality software.
Remember that bug where their own headers triggered a warning?

Richard
 
P

Philip Potter

jacob said:
Under the highest warning level, a compiler should warn
about

int main()

since it is an obsolete syntax. Note that lcc-win does NOT
warn in the default warning level.

I agree with you (pretending for the moment you said "obsolescent" and not
"obsolete"). But you said:

It should *not* issue a warning for incorrect syntax, because the syntax is not
incorrect. It can issue a warning for obsolescent syntax if it likes.

Phil
 
F

Francine.Neary

Here I am with you.

6.9.1 Function definitions

states in paragraph 7:

The declarator in a function definition specifies the name of the
function being defined and the identifiers of its parameters. If the
declarator includes a parameter type list, the list also specifies
the types of all the parameters; such a declarator also serves as a
function prototype for later calls to the same function in the same
translation unit. If the declarator includes an identifier list,139)
the types of the parameters shall be declared in a following
declaration list. In either case, the type of each parameter is
adjusted as described in 6.7.5.3 for a parameter type list; the
resulting type shall be an object type.

This suggests to me that a function definition with no "parameter tpye
list" (note that int main() has an empty "identifier list" -- no the
same at all) is not a prototype. Given the special execption I quote
above it seems likely that this is a bug in the standard, but there it
is. I think you are right that int main() does not act as a prototype
for subsequent calls.

As I explained elsewhere, I read this differently. The key sentence is
"If the declarator includes a parameter type list, the list also
specifies the types of all the parameters; such a declarator also
serves as a function prototype for later calls to the same function in
the same translation unit."

What does it mean to "include a parameter type list"? Well, the
Standard tells us, in 6.5.4.3! It differentiates between a parameter
type list, which "specifies the types of the parameters of a
function", and an identifier list, which "declares only the
identifiers of the parameters of a function".

The seemingly ambiguous case is int main() { ... }. This could either
be regarded as main with an empty parameter-type-list, or main with a
non-supplied optional identifier-list. Which is it? Well, 6.5.4.3
comes to the rescue again and clears this up for us: for a function
DEFINITION, an empty list of parameters is interpreted in the first
way, specifying that the function has no parameters. (As it happens,
in a declaration that isn't a definition, it's interpreted in the
second way, giving no information about parameters, but that's
irrelevant here.)

Therefore, in the definition int main() { ... }, () is the empty
parameter-type-list, and therefore it serves as a function prototype
for later calls to main.
Ah, but that is not the meaning of "for later calls to the same
function in the translation unit". You would be right to complain
about:

int main()
{
return main();

}

because the subsequent call has no prototype.

No, as above.
 
K

Kenneth Brody

On Sep 27, 9:49 am, jacob navia <[email protected]> wrote:

[... "int main() { code }" versus "int main(void) { code } " ...]
(6.7.1) If the declarator includes a parameter type list... such a
declarator also serves as a function prototype for later calls to the
same function in the same translation unit.

Now you need to observe that the empty list is a list...
[...]

Well, is my compiler broken then?

==========
#include <stdio.h>

int foo()
{
return 1;
}

int main(void)
{
foo();
foo(10);
}
==========

I get no warnings, even with warnings at the max. If I change the
"int foo()" to "int foo(void)", it warns me (even at the default
warning level) that "foo: declared with 'void' parameter list". If
you are saying that "int foo() { code }" does, in fact, prototype
foo() as having no parameters, then shouldn't my compiler warn me
about it, as it does when I explicitly state the void parameter list?

Now, I'm certainly not claiming that my compiler's output is the
gospel, just food for thought.

I'm curious what gcc with the "turn pedantry to the max" set of
switches says about the above?

--
+-------------------------+--------------------+-----------------------+
| Kenneth J. Brody | www.hvcomputer.com | #include |
| kenbrody/at\spamcop.net | www.fptech.com | <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------+
Don't e-mail me at: <mailto:[email protected]>
 
J

jacob navia

Kenneth said:
On Sep 27, 9:49 am, jacob navia <[email protected]> wrote:

[... "int main() { code }" versus "int main(void) { code } " ...]
(6.7.1) If the declarator includes a parameter type list... such a
declarator also serves as a function prototype for later calls to the
same function in the same translation unit.

Now you need to observe that the empty list is a list...
[...]

Well, is my compiler broken then?

==========
#include <stdio.h>

int foo()
{
return 1;
}

int main(void)
{
foo();
foo(10);
}
==========

I get no warnings, even with warnings at the max. If I change the
"int foo()" to "int foo(void)", it warns me (even at the default
warning level) that "foo: declared with 'void' parameter list". If
you are saying that "int foo() { code }" does, in fact, prototype
foo() as having no parameters, then shouldn't my compiler warn me
about it, as it does when I explicitly state the void parameter list?

Now, I'm certainly not claiming that my compiler's output is the
gospel, just food for thought.

I'm curious what gcc with the "turn pedantry to the max" set of
switches says about the above?

Nothing!

[root@gateway tmp]# gcc -Wall -pedantic t12.c
t12.c: In function `main':
t12.c:12: warning: control reaches end of non-void function
[root@gateway tmp]#
 
B

Ben Bacarisse

Kenneth Brody said:
On Sep 27, 9:49 am, jacob navia <[email protected]> wrote:

[... "int main() { code }" versus "int main(void) { code } " ...]
(6.7.1) If the declarator includes a parameter type list... such a
declarator also serves as a function prototype for later calls to the
same function in the same translation unit.

Now you need to observe that the empty list is a list...
[...]

Well, is my compiler broken then?

==========
#include <stdio.h>

int foo()
{
return 1;
}

int main(void)
{
foo();
foo(10);
}
==========

Not broken, no.
I get no warnings, even with warnings at the max. If I change the
"int foo()" to "int foo(void)", it warns me (even at the default
warning level) that "foo: declared with 'void' parameter list". If
you are saying that "int foo() { code }" does, in fact, prototype
foo() as having no parameters,

No. int foo() { code } is not a prototype for foo, so foo(10) is not a
constraint violation -- no diagnostic required. Gcc on max verbosity
tells me that the definition of foo does not constitute a prototype for
it which is certainly useful.

Function definitions like those of foo are peculiar. 6.7.5.3-14 (of
my non-authoritative draft) states that foo is a function that "has no
parameters" and 6.9.1-7 states that a definition only acts as
prototype if it includes a parameter list.

The call foo(10) is undefined due the wording in 6.5.2.2-6:

If the expression that denotes the called function has a type that
does not include a prototype, the integer promotions are performed
on each argument, and arguments that have type float are promoted
to double. These are called the default argument promotions. If the
number of arguments does not equal the number of parameters, the
behavior is undefined.
 
J

jacob navia

Ben said:
Kenneth Brody said:
On Sep 27, 9:49 am, jacob navia <[email protected]> wrote:
[... "int main() { code }" versus "int main(void) { code } " ...]
But a definition serves as a prototype. I'd expect this warning to
mean I'd called a function with no prototype in scope, which isn't the
case here.
This means that main has no prototype since you did NOT
provide a prototype and main *IS* always called!
(6.7.1) If the declarator includes a parameter type list... such a
declarator also serves as a function prototype for later calls to the
same function in the same translation unit.

Now you need to observe that the empty list is a list...
[...]

Well, is my compiler broken then?

==========
#include <stdio.h>

int foo()
{
return 1;
}

int main(void)
{
foo();
foo(10);
}
==========

Not broken, no.
I get no warnings, even with warnings at the max. If I change the
"int foo()" to "int foo(void)", it warns me (even at the default
warning level) that "foo: declared with 'void' parameter list". If
you are saying that "int foo() { code }" does, in fact, prototype
foo() as having no parameters,

No. int foo() { code } is not a prototype for foo, so foo(10) is not a
constraint violation -- no diagnostic required. Gcc on max verbosity
tells me that the definition of foo does not constitute a prototype for
it which is certainly useful.

Then, the warning I am issuing is justified!
 
B

Ben Bacarisse

As I explained elsewhere, I read this differently. The key sentence is
"If the declarator includes a parameter type list, the list also
specifies the types of all the parameters; such a declarator also
serves as a function prototype for later calls to the same function in
the same translation unit."

What does it mean to "include a parameter type list"? Well, the
Standard tells us, in 6.5.4.3! It differentiates between a parameter
type list, which "specifies the types of the parameters of a
function", and an identifier list, which "declares only the
identifiers of the parameters of a function".

The seemingly ambiguous case is int main() { ... }. This could either
be regarded as main with an empty parameter-type-list, or main with a
non-supplied optional identifier-list. Which is it?

The syntax makes it quite clear, I think. See below...
Well, 6.5.4.3
comes to the rescue again and clears this up for us: for a function
DEFINITION, an empty list of parameters is interpreted in the first
way, specifying that the function has no parameters.

Yes but that section does not tell us how to disambiguate the () in
the function definition -- it tell us what it *means* but not what is
*is*. In fact it is not ambiguous if you look at the syntax. A
parameter type list may not be empty whereas an identifier list can
be. (Check for yourself, readers, because the syntax is complex and I
may well have got that wrong, though I have checked as carefully as I
can.)

I am open to persuasion (that int foo() { ... } acts as a prototype)
but you will have to persuade the gcc people as well! -- OK you need
to ask for -Wstrict-prototypes, but at least you can.
 
C

Chris Hills

Richard Heathfield said:
Joachim Schmitz said:


Nope. I can read a map, same as anyone, and on my map of the universe it is
clearly marked as the English Channel. I don't object to calling it the
South Sea, though, if you'd prefer to do that.


I'm glad you think so. Just so long as Europe stays on its side of the
water, you can think what you like. :)

The sooner we get the Euro and fully integrated with Europe the better.
 
F

Francine.Neary

The syntax makes it quite clear, I think. See below...


Yes but that section does not tell us how to disambiguate the () in
the function definition -- it tell us what it *means* but not what is
*is*. In fact it is not ambiguous if you look at the syntax. A
parameter type list may not be empty whereas an identifier list can
be. (Check for yourself, readers, because the syntax is complex and I
may well have got that wrong, though I have checked as carefully as I
can.)

I don't have the energy to figure it out, but I'll take your word for
it... especially since, re-reading 6.5.4.3 in context, it does seem
that "empty list" refers to an empty identifier list.

So that's really ugly :(

int main() { ... } and int main(void) { ... } do indeed have very
subtly different semantics, which is dumb: after seeing either of them
the compiler knows exactly the signature of main, but only in one case
is it allowed to use this knowledge if it encounters main later in the
same translation unit. Yuck!
 
?

=?iso-2022-kr?q?=1B=24=29CHarald_van_D=0E=29=26=0F

jacob said:
Martin said:
Heinrich Pumpernickel wrote:
int main()
[...]
lcc -A -ansic -O long.c -o long.obj
Warning c:\tmp\long.c: 4 old-style function definition for 'main'
This warning is bogus and incorrect.
There is nothing "old-style" about it.

6.11.6 Function declarators
1 The use of function declarators with empty parentheses (not prototype-
format parameter type declarators) is an obsolescent feature.
6.11.7 Function definitions
1 The use of function definitions with separate parameter identifier and
declaration lists (not prototype-format parameter type and identifier
declarators) is an obsolescent feature.

() in a function definition is the type of function definition having a
parameter identifier list, not a parameter declaration list. This is
specified by the grammar. I suppose you could try to argue that "old
style" is not the same as obsolescent, but:

6.7.5.3 Function declarators (including prototypes)
15 For two function types to be compatible, both shall specify compatible
return types.125) [...]
125) If both function types are "old style", parameter types are not
compared.
 
J

jacob navia

I don't have the energy to figure it out, but I'll take your word for
it... especially since, re-reading 6.5.4.3 in context, it does seem
that "empty list" refers to an empty identifier list.

So that's really ugly :(

int main() { ... } and int main(void) { ... } do indeed have very
subtly different semantics, which is dumb: after seeing either of them
the compiler knows exactly the signature of main, but only in one case
is it allowed to use this knowledge if it encounters main later in the
same translation unit. Yuck!

OK Ben, then, you agree that a warning at the highest warning
level is justified!
 
K

Keith Thompson

jacob navia said:
Then, the warning I am issuing is justified!

Which one?

For context, here are the three warnings issued for 'int main() { ... }':

Warning c:\tmp\long.c: 4 old-style function definition for 'main'
Warning c:\tmp\long.c: 4 missing prototype for 'main'
Warning c:\tmp\long.c: 4 'int main()' is a non-ANSI definition

The first warning is, IMHO, quite correct and reasonable. Note that
using parentheses for a function that takes no arguments is an easier
mistake to make than using a K&R-style definition with one or more
parameters. I suggest recognizing that special case and suggesting
changing '()' to '(void)'.

The second one is ok. A prototype is indeed missing, but the language
doesn't require a prototype. But if the compiler is invoked in a mode
that specifically requires prototypes, it's a valid warning.

The third one is simply incorrect. It says nothing that the first
warning didn't already tell you, and it's factually incorrect since
the ANSI^H^H^H^H ISO standard specifically allows old-style
declarations.

And *why* does the messsage refer to ANSI rather than ISO?
 
K

Keith Thompson

Ben Bacarisse said:
(e-mail address removed) writes: [...]
The seemingly ambiguous case is int main() { ... }. This could either
be regarded as main with an empty parameter-type-list, or main with a
non-supplied optional identifier-list. Which is it?

The syntax makes it quite clear, I think. See below...
Well, 6.5.4.3
comes to the rescue again and clears this up for us: for a function
DEFINITION, an empty list of parameters is interpreted in the first
way, specifying that the function has no parameters.

Yes but that section does not tell us how to disambiguate the () in
the function definition -- it tell us what it *means* but not what is
*is*. In fact it is not ambiguous if you look at the syntax. A
parameter type list may not be empty whereas an identifier list can
be. (Check for yourself, readers, because the syntax is complex and I
may well have got that wrong, though I have checked as carefully as I
can.)

I am open to persuasion (that int foo() { ... } acts as a prototype)
but you will have to persuade the gcc people as well! -- OK you need
to ask for -Wstrict-prototypes, but at least you can.

Yes, the grammar is in 6.7.5:

parameter-type-list:
parameter-list
parameter-list , ...

parameter-list:
parameter-declaration
parameter-list , parameter-declaration

A parameter-type-list cannot be empty.
 
J

jacob navia

Keith said:
Which one?

The second one. The discussion is about the supposed difference
between () in a function declaration, where it means "indeterminate
number of parameters" and a function definition, where some people
here say the space between the () would be "overloaded" to mean
"void".

That interpretation is not correct IMHO.
For context, here are the three warnings issued for 'int main() { ... }':

Warning c:\tmp\long.c: 4 old-style function definition for 'main'
Warning c:\tmp\long.c: 4 missing prototype for 'main'
Warning c:\tmp\long.c: 4 'int main()' is a non-ANSI definition

The first warning is, IMHO, quite correct and reasonable. Note that
using parentheses for a function that takes no arguments is an easier
mistake to make than using a K&R-style definition with one or more
parameters. I suggest recognizing that special case and suggesting
changing '()' to '(void)'.

The second one is ok. A prototype is indeed missing, but the language
doesn't require a prototype. But if the compiler is invoked in a mode
that specifically requires prototypes, it's a valid warning.

The third one is simply incorrect. It says nothing that the first
warning didn't already tell you, and it's factually incorrect since
the ANSI^H^H^H^H ISO standard specifically allows old-style
declarations.

And *why* does the messsage refer to ANSI rather than ISO?


OK, will replace ANSI by ISO. I issue that third warning always
when I find a declaration of main that doesn't *exactly*
fit into int main(void) or int main(int argc,char *argv[])

At maximum warning level that is justified.
 
J

jacob navia

Keith said:
Ben Bacarisse said:
(e-mail address removed) writes: [...]
The seemingly ambiguous case is int main() { ... }. This could either
be regarded as main with an empty parameter-type-list, or main with a
non-supplied optional identifier-list. Which is it?
The syntax makes it quite clear, I think. See below...
Well, 6.5.4.3
comes to the rescue again and clears this up for us: for a function
DEFINITION, an empty list of parameters is interpreted in the first
way, specifying that the function has no parameters.
Yes but that section does not tell us how to disambiguate the () in
the function definition -- it tell us what it *means* but not what is
*is*. In fact it is not ambiguous if you look at the syntax. A
parameter type list may not be empty whereas an identifier list can
be. (Check for yourself, readers, because the syntax is complex and I
may well have got that wrong, though I have checked as carefully as I
can.)

I am open to persuasion (that int foo() { ... } acts as a prototype)
but you will have to persuade the gcc people as well! -- OK you need
to ask for -Wstrict-prototypes, but at least you can.

Yes, the grammar is in 6.7.5:

parameter-type-list:
parameter-list
parameter-list , ...

parameter-list:
parameter-declaration
parameter-list , parameter-declaration

A parameter-type-list cannot be empty.

That is confirmed in DR #317 as Harald van Dijk
told me in comp.std.c
 
J

jacob navia

The committee already discussed this question. Here is the answer:
------------------------------------------------------------------
Defect Report #317
Submitter: UK C Panel
Submission Date: 2005-03-04
Source: Joseph Myers <[email protected]>
Reference Document: ISO/IEC WG14 N1105
Version: 1.3
Date: 2006-04-04
Subject: Function definitions with empty parentheses

Summary

I believe the intent of C is that old-style function definitions with
empty parentheses do not give the function a type including a prototype
for the rest of the translation unit. For example,

void f(){}
void g(){if(0)f(1);}

is valid.

6.9.1#7 specifies that if the declarator in the function definition
includes a parameter type list, it also serves as a prototype for the
rest of the translation unit. It does not specify that nothing else
serves as a prototype. Some readers of the standard interpret
6.7.5.3#14, "An empty list in a function declarator that is part of a
definition of that function specifies that the function has no
parameters.", as specifying that it provides a prototype.

Question 1: Does such a function definition give the function a type
including a prototype for the rest of the translation unit?

Question 2: Is the above translation unit valid?

Suggested Technical Corrigendum

Committee Response

The grammar states that an empty parens stands for an empty identifier
list not an empty parameter-type-list.

The answer to question #1 is NO, and to question #2 is YES. There are no
constraint violations, however, if the function call were executed it
would have undefined behavior. See 6.5.2.2;p6.
 
B

Ben Bacarisse

jacob navia said:
Ben said:
Kenneth Brody said:
(e-mail address removed) wrote:
[... "int main() { code }" versus "int main(void) { code } " ...]

But a definition serves as a prototype. I'd expect this warning to
mean I'd called a function with no prototype in scope, which isn't the
case here.
This means that main has no prototype since you did NOT
provide a prototype and main *IS* always called!
(6.7.1) If the declarator includes a parameter type list... such a
declarator also serves as a function prototype for later calls to the
same function in the same translation unit.

Now you need to observe that the empty list is a list...
[...]

Well, is my compiler broken then?

==========
#include <stdio.h>

int foo()
{
return 1;
}

int main(void)
{
foo();
foo(10);
}
==========

Not broken, no.
I get no warnings, even with warnings at the max. If I change the
"int foo()" to "int foo(void)", it warns me (even at the default
warning level) that "foo: declared with 'void' parameter list". If
you are saying that "int foo() { code }" does, in fact, prototype
foo() as having no parameters,

No. int foo() { code } is not a prototype for foo, so foo(10) is not a
constraint violation -- no diagnostic required. Gcc on max verbosity
tells me that the definition of foo does not constitute a prototype for
it which is certainly useful.

Then, the warning I am issuing is justified!

If you mean the "missing prototype" one, then I don't like the wording
because nothing is really missing (prototypes are not *required*) but it
does help a bit and it is not wrong. gcc says: "function declaration
isn’t a prototype" which is direct and to the point.
 
C

Chris Torek

int main() { ... } and int main(void) { ... } do indeed have very
subtly different semantics ...

Yes: the latter provides a prototype declaration of the function
(in this case, of main()), as if one had written:

int main(void);
int main(void) { ... }

The former fails to provide a prototype declaration, only a
type-declaration, as if one had written:

int main();
int main() { ... }
which is dumb: after seeing either of them the compiler knows
exactly the signature of main, but only in one case is it allowed
to use this knowledge if it encounters main later in the
same translation unit. Yuck!

Change the word "allowed" to "required", and you have it precisely.

A compiler is always allowed to produce extra diagnostics. It
is only *required* to produce a diagnostic for this particular
error for a prototype mismatch. Hence, the code fragment:

/* x.c */
int f();
int g(void);

int h(void) {
return f(0) + g(0);
}

requires a diagnostic, because g(0) supplies an argument where the
compiler is required to remember that g() takes no arguments. If
the compiler can somehow tell that f() also takes no arguments --
e.g., by looking at a separate file like "f.c" or "f.o", or looking
elsewhere in this same file (x.c) and finding the actual code for
f(), or reading the design documentation for the project, or perhaps
even by reading the programmer's mind -- it is *allowed* to warn
about f().

(Writing a compiler that reads the project documentation and/or
the programmer's mind is perhaps a little ambitious. :) Having
the compiler -- which includes the thing usually called "the linker",
in this case -- examine every file that is combined to make the
final executable is, however, quite feasible. The diagnostic for
the mismatch between an f() that takes no arguments and the call
f(0) may wind up looking something like "unable to find symbol
$function$int$f$int$", perhaps, although a "nice" linker might also
then back-translate that to "unable to find int f(int); I did find
an int f(void) but that does not match; perhaps the call at line
45 in h.c is incorrect".)
 

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,776
Messages
2,569,603
Members
45,195
Latest member
tewan

Latest Threads

Top