Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

(part 21) Han from China answers your C questions

4 views
Skip to first unread message

Nomen Nescio

unread,
Nov 14, 2008, 3:00:04 PM11/14/08
to
its urgent.pls help me.

mona said:
> hi,i urgently need a project including graphics,pointers.
> not a major one.
> pls send at "jahanm...@gmail.com"

Hey, mona.

Post full details, and we'll be happy to see what we can do
for you.

In the meantime, here's a program that meets the specifications:

#include <stdio.h>

int
main(void)
{
/*
* What we have here is a simple graphics output.
* We satisfy the requirement for pointers in two ways:
* (1) we have a graphics pointer (or arrow)
* (2) the argument to printf() decays to a pointer
*/
printf(" ===> \n");
return 0;
}

Yours,
Han from China

Lew Pitcher

unread,
Nov 14, 2008, 3:11:55 PM11/14/08
to
On November 14, 2008 15:00, in comp.lang.c, Nomen Nescio (nob...@dizum.com)
wrote:

> its urgent.pls help me.
>
> mona said:
>> hi,i urgently need a project including graphics,pointers.

[snip]


> In the meantime, here's a program that meets the specifications:
>
> #include <stdio.h>
>
> int
> main(void)
> {
> /*
> * What we have here is a simple graphics output.
> * We satisfy the requirement for pointers in two ways:
> * (1) we have a graphics pointer (or arrow)
> * (2) the argument to printf() decays to a pointer
> */
> printf(" ===> \n");

Overkill

> return 0;
> }

Try

#include <stdio.h>

int main(void)
{
puts(" ---> ")
return 0;
}

--
Lew Pitcher

Master Codewright & JOAT-in-training | Registered Linux User #112576
http://pitcher.digitalfreehold.ca/ | GPG public key available by request
---------- Slackware - Because I know what I'm doing. ------


Andrey Tarasevich

unread,
Nov 14, 2008, 3:28:31 PM11/14/08
to
Lew Pitcher wrote:
>
> #include <stdio.h>
>
> int main(void)
> {
> puts(" ---> ")
> return 0;
> }
>

Overkill

#include <stdio.h>

int main(void) {
puts(" --> ")
}

--
Best regards,
Andrey Tarasevich

Lew Pitcher

unread,
Nov 14, 2008, 3:46:41 PM11/14/08
to
On November 14, 2008 15:11, in comp.lang.c, Lew Pitcher
(lpit...@teksavvy.com) wrote:

[snip]


>
> #include <stdio.h>
>
> int main(void)
> {
> puts(" ---> ")

gaak! I missed a semicolon here.

> return 0;
> }
>

I promise to be more carefull next time

s0s...@gmail.com

unread,
Nov 14, 2008, 5:30:07 PM11/14/08
to
On Nov 14, 3:28 pm, Andrey Tarasevich <andreyta...@hotmail.com>
wrote:

> Lew Pitcher wrote:
>
> >   #include <stdio.h>
>
> >   int main(void)
> >   {
> >     puts("  --->  ")
> >     return 0;
> >   }
>
> Overkill
>
>    #include <stdio.h>
>
>    int main(void) {
>      puts(" --> ")
>    }

Overkill. The #include line will bring in a bunch of stuff :-)

int main(void) { int puts(const char *); puts(" --> "); }

Sebastian

Ralf Damaschke

unread,
Nov 15, 2008, 2:59:35 AM11/15/08
to
s0suk3 wrote:

Overkill. No need for a prototype (even in C99).

int main(void) { int puts(); puts(" --> "); }

-- Ralf

Richard Heathfield

unread,
Nov 15, 2008, 3:09:07 AM11/15/08
to
Ralf Damaschke said:

int main() { int puts(); puts(" --> "; }

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999

Harald van Dijk

unread,
Nov 15, 2008, 5:04:11 AM11/15/08
to
On Sat, 15 Nov 2008 07:59:35 +0000, Ralf Damaschke wrote:
> s0suk3 wrote:
>> Overkill. The #include line will bring in a bunch of stuff :-)
>>
>> int main(void) { int puts(const char *); puts(" --> "); }
>
> Overkill. No need for a prototype (even in C99).
>
> int main(void) { int puts(); puts(" --> "); }

This doesn't convert the pointer to the string from char * to const char
*. I doubt any implementation will even notice, but you need either the
prototype, or you need to change the call to puts((const char *) " --> ");
for it to be valid.

Flash Gordon

unread,
Nov 15, 2008, 6:40:34 AM11/15/08
to
Harald van Dijk wrote, On 15/11/08 10:04:

There are other ways, such as using a variable, and the spaces are
overkill...

int main(void){int puts();const char*s=" --> ";puts(s);}
int main(void){int puts();puts((const char*)" --> ");}
--
Flash Gordon
If spamming me sent it to sm...@spam.causeway.com
If emailing me use my reply-to address
See the comp.lang.c Wiki hosted by me at http://clc-wiki.net/

pete

unread,
Nov 15, 2008, 7:35:48 AM11/15/08
to
Richard Heathfield wrote:
> Ralf Damaschke said:
>
>> s0suk3 wrote:
>>
>>> On Nov 14, 3:28 pm, Andrey Tarasevich <andreyta...@hotmail.com>
>>> wrote:
>>>> Lew Pitcher wrote:
>>>>
>>>>> #include <stdio.h>
>>>>> int main(void)
>>>>> {
>>>>> puts(" ---> ")
>>>>> return 0;
>>>>> }
>>>> Overkill
>>>>
>>>> #include <stdio.h>
>>>>
>>>> int main(void) {
>>>> puts(" --> ")
>>>> }
>>> Overkill. The #include line will bring in a bunch of stuff :-)
>>>
>>> int main(void) { int puts(const char *); puts(" --> "); }
>> Overkill. No need for a prototype (even in C99).
>>
>> int main(void) { int puts(); puts(" --> "); }
>
> Overkill. No need for a prototype (even in C99).
>
> int main() { int puts(); puts(" --> "; }

What do you mean by "(even in C99)" ?

There is no implicit function declaration in C99.
That's a C89 feature.

--
pete

Harald van Dijk

unread,
Nov 15, 2008, 7:54:16 AM11/15/08
to

Yes, but unprototyped functions are allowed even in C99. Ralf Damaschke
removed "const char *" from the declaration of puts. Richard Heathfield
removed "void" from the definition of main. Both kept the one called
function explicitly declared. There is no implicit function declaration
here.

Keith Thompson

unread,
Nov 15, 2008, 11:57:29 AM11/15/08
to
Richard Heathfield <r...@see.sig.invalid> writes:
> Ralf Damaschke said:
>> s0suk3 wrote:
>>> On Nov 14, 3:28 pm, Andrey Tarasevich <andreyta...@hotmail.com>
>>> wrote:
>>>> Lew Pitcher wrote:
>>>>
>>>> > #include <stdio.h>
>>>>
>>>> > int main(void)
>>>> > {
>>>> > puts(" ---> ")
>>>> > return 0;
>>>> > }
>>>>
>>>> Overkill
>>>>
>>>> #include <stdio.h>
>>>>
>>>> int main(void) {
>>>> puts(" --> ")
>>>> }
>>>
>>> Overkill. The #include line will bring in a bunch of stuff :-)
>>>
>>> int main(void) { int puts(const char *); puts(" --> "); }
>>
>> Overkill. No need for a prototype (even in C99).
>>
>> int main(void) { int puts(); puts(" --> "); }
>
> Overkill. No need for a prototype (even in C99).
>
> int main() { int puts(); puts(" --> "; }

Actually, that's debatable -- and it's been debated here before.
The argument is that declaration "int main()" isn't equivalent to
"int main(void)", since the former permits (with undefined behavior)
"main(42)" while the latter makes it a constraint violation; see
C99 5.1.2.2.1.

--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Richard Heathfield

unread,
Nov 15, 2008, 12:12:57 PM11/15/08
to
Keith Thompson said:

> Richard Heathfield <r...@see.sig.invalid> writes:
>> Ralf Damaschke said:
>>> s0suk3 wrote:

<snip>


>>>> int main(void) { int puts(const char *); puts(" --> "); }
>>>
>>> Overkill. No need for a prototype (even in C99).
>>>
>>> int main(void) { int puts(); puts(" --> "); }
>>
>> Overkill. No need for a prototype (even in C99).
>>
>> int main() { int puts(); puts(" --> "; }
>
> Actually, that's debatable -- and it's been debated here before.
> The argument is that declaration "int main()" isn't equivalent to
> "int main(void)", since the former permits (with undefined behavior)
> "main(42)" while the latter makes it a constraint violation; see
> C99 5.1.2.2.1.

Yes, but the above code doesn't *contain* main(42). If you simply meant
"it's better to use int main(void) than int main()", I agree. But that
wasn't the cake we were baking on this occasion.

Harald van Dijk

unread,
Nov 15, 2008, 12:29:27 PM11/15/08
to
On Sat, 15 Nov 2008 17:12:57 +0000, Richard Heathfield wrote:
> Keith Thompson said:
>> Richard Heathfield <r...@see.sig.invalid> writes:
>>> Ralf Damaschke said:
>>>> s0suk3 wrote:
> <snip>
>>>>> int main(void) { int puts(const char *); puts(" --> "); }
>>>>
>>>> Overkill. No need for a prototype (even in C99).
>>>>
>>>> int main(void) { int puts(); puts(" --> "); }
>>>
>>> Overkill. No need for a prototype (even in C99).
>>>
>>> int main() { int puts(); puts(" --> "; }
>>
>> Actually, that's debatable -- and it's been debated here before. The
>> argument is that declaration "int main()" isn't equivalent to "int
>> main(void)", since the former permits (with undefined behavior)
>> "main(42)" while the latter makes it a constraint violation; see C99
>> 5.1.2.2.1.
>
> Yes, but the above code doesn't *contain* main(42).

But if main() isn't equivalent to main(void), and main must be defined as
int main(void), int main(int argc, char *argv[]), or equivalent, then
defining it as main() is invalid, even if you don't call main(42). That's
the point I believe Keith Thompson was making.

(Personally, I believe int main() is valid.)

Richard Heathfield

unread,
Nov 15, 2008, 12:44:32 PM11/15/08
to
Harald van D?k said:

<snip>



> But if main() isn't equivalent to main(void), and main must be defined as
> int main(void), int main(int argc, char *argv[]), or equivalent, then
> defining it as main() is invalid, even if you don't call main(42). That's
> the point I believe Keith Thompson was making.

Oh, I see.

> (Personally, I believe int main() is valid.)

I agree. Note that int main() - in a function *definition* - defines main
as taking no parameters. The relevant quote is in 3.5.4.3: "An empty list
in a function declarator that is part of a function definition specifies
that the function has no parameters. The empty list in a function
declarator that is not part of a function definition specifies that no
information about the number or types of the parameters is supplied."

Almost identical wording appears in 6.7.5.3(14) of C99. Incidentally, the
wording is slightly tighter in C99 - which is actually quite interesting,
because it reveals a slight flaw in the wording of the above, but the
differences aren't relevant to the current case.

Keith Thompson

unread,
Nov 15, 2008, 2:04:03 PM11/15/08
to
Richard Heathfield <r...@see.sig.invalid> writes:
> Harald van D?k said:
>
> <snip>
>
>> But if main() isn't equivalent to main(void), and main must be defined as
>> int main(void), int main(int argc, char *argv[]), or equivalent, then
>> defining it as main() is invalid, even if you don't call main(42). That's
>> the point I believe Keith Thompson was making.
>
> Oh, I see.
>
>> (Personally, I believe int main() is valid.)
>
> I agree. Note that int main() - in a function *definition* - defines main
> as taking no parameters. The relevant quote is in 3.5.4.3: "An empty list
> in a function declarator that is part of a function definition specifies
> that the function has no parameters. The empty list in a function
> declarator that is not part of a function definition specifies that no
> information about the number or types of the parameters is supplied."
>
> Almost identical wording appears in 6.7.5.3(14) of C99. Incidentally, the
> wording is slightly tighter in C99 - which is actually quite interesting,
> because it reveals a slight flaw in the wording of the above, but the
> differences aren't relevant to the current case.

Yes, either "int main(void) { ... }" or "int main() { ... }" defines
main as taking no parameters; they're similar in that way. But one
similarity doesn't make them equivalent.

Here's what the standard says (C99 5.1.2.2.1):

The function called at program startup is named main. The
implementation declares no prototype for this function. It shall
be defined with a return type of int and with no parameters:

int main(void) { /* ... */ }

or with two parameters (referred to here as argc and argv, though
any names may be used, as they are local to the function in which
they are declared):

int main(int argc, char *argv[]) { /* ... */ }

or equivalent; or in some other implementation-defined manner.

The following two declarations:

int x;
double x;

are similar in that they both declare objects named "x". They're not
equivalent, though, because they declare objects of different types.
Even putting them in a program where the difference has no visible
effect doesn't make them equivalent; the programs might be effectively
equivalent, but the declarations aren't. (My argument here is just a
reasonable use of the word "equivalent".)

The following two function definitions:

int main() { return 0; }
int main(void) { return 0; }

are similar in that they both declare and define a function called
"main". They differ in that, for example, one makes the call
"main(42)", appearing in another function in the same translation unit
following the above definition, invoke undefined behavior, while the
other makes it a constraint violation.

The standard doesn't say that the definition of main must be very
similar to "int main(void) { /* ... */ }", differing only in ways that
have no effect on the particular program being considered. It says
that it must be *equivalent* (or it must follow one of the other two
options).

In practice, most or all C compilers do support "int main()" with the
obvious semantics. If my interpretation is correct (and no, I'm not
100% certain of that), then "int main()", in an implementation that
doesn't document it, invokes undefined behavior; accept it is
perfectly legal.

Harald van Dijk

unread,
Nov 15, 2008, 2:33:12 PM11/15/08
to
On Sat, 15 Nov 2008 11:04:03 -0800, Keith Thompson wrote:
> Yes, either "int main(void) { ... }" or "int main() { ... }" defines
> main as taking no parameters; they're similar in that way. But one
> similarity doesn't make them equivalent.

I'd like to stay out of the main discussion, but I'm curious how you feel
about this?

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

Is this equivalent to

int main(void) {
/* ... */
}

? If not, in what way are these not equivalent?

Perhaps also interesting is that

int main(int argc, char *argv[]) {
/* ... */
}

is not equivalent to

int main(int argc, char *argv[]);
int main(argc, argv)
int argc;
char *argv[];
{
/* ... */
}

because the latter allows main to be called as

int (*mainptr)() = &main;
(*mainptr)(1u, (char **) 0);

while the former doesn't, but this doesn't apply to () versus (void).

pete

unread,
Nov 15, 2008, 4:37:42 PM11/15/08
to
Harald van Dijk wrote:
> On Sat, 15 Nov 2008 07:35:48 -0500, pete wrote:
>> Richard Heathfield wrote:
>>> Ralf Damaschke said:
>>>> s0suk3 wrote:
>>>>> int main(void) { int puts(const char *); puts(" --> "); }
>>>> Overkill. No need for a prototype (even in C99).
>>>>
>>>> int main(void) { int puts(); puts(" --> "); }
>>> Overkill. No need for a prototype (even in C99).
>>>
>>> int main() { int puts(); puts(" --> "; }
>> What do you mean by "(even in C99)" ?
>>
>> There is no implicit function declaration in C99. That's a C89 feature.
>
> Yes, but unprototyped functions are allowed even in C99.

I had not noticed the function declaration
inside of the definition of main, and so
I missed the whole point of what was being discussed.

--
pete

Ralf Damaschke

unread,
Nov 16, 2008, 10:46:04 AM11/16/08
to
Harald van =?UTF-8?b?RMSzaw==?= wrote:

> On Sat, 15 Nov 2008 07:59:35 +0000, Ralf Damaschke wrote:
>> int main(void) { int puts(); puts(" --> "); }
>
> This doesn't convert the pointer to the string from char * to const
> char *.

Surprisingly (for me) I am afraid you are right.

-- Ralf

Tim Rentsch

unread,
Nov 18, 2008, 1:11:58 PM11/18/08
to
Keith Thompson <ks...@mib.org> writes:

> doesn't document it, invokes undefined behavior; [...]

A good argument, and well presented.

The argument hinges on the function definition

int main(){ return 0; }

not supplying a prototype for main(). Is that in fact the case? I
would like to give an argument that this definition does in fact
supply a prototype for main(). First the definition for prototype,
given in the last sentence of 6.2.1p2:

For each different entity that an identifier designates, the
identifier is visible (i.e., can be used) only within a region of
program text called its scope. Different entities designated by the
same identifier either have different scopes, or are in different
name spaces. There are four kinds of scopes: function, file, block,
and function prototype. (A function prototype is a declaration of a
function that declares the types of its parameters.)

Now a relevant paragraph from the section on function declarators,
namely 6.7.3p14:

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.(126)

Note the second sentence, and contrast it with the third sentence.
Also, this paragraph being in the section on function /declarators/
is germane to the argument. The explicit specification that the
declared function has no parameters means this declaration does
indeed declare the types of its parameters.

The footnote reference (126) says:

126) See ``future language directions'' (6.11.6).

This section and the one after it merit examination:

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.

Again, contrast the wording in the two paragraphs. The wording
identifying "not prototype-format" style is different in the
case of function definitions, which supports the proposition.

The opposite side of this argument is (a) 6.11.6 would seem to apply
to function declarators /in definitions/ in addition to function
declarations /not/ in definitions, and (b) wording in other places in
the standard suggests "prototype" is synonymous with there being a
parameter-type-list.

Looking at both sides, the explicit statement in 6.7.3p14, especially
in contrast to the corresponding statement for declarations not part
of a definition, makes the argument "for" seem a little stronger than
the argument "against". Is there a crushing counter-argument that
I'm missing?

[My apologies if part of this message gets posted twice... editor error]

Tim Rentsch

unread,
Nov 18, 2008, 1:33:34 PM11/18/08
to
Harald van =?UTF-8?b?RMSzaw==?= <tru...@gmail.com> writes:

> Perhaps also interesting is that
>
> int main(int argc, char *argv[]) {
> /* ... */
> }
>
> is not equivalent to
>
> int main(int argc, char *argv[]);
> int main(argc, argv)
> int argc;
> char *argv[];
> {
> /* ... */
> }
>
> because the latter allows main to be called as
>
> int (*mainptr)() = &main;
> (*mainptr)(1u, (char **) 0);
>
> while the former doesn't, but this doesn't apply to () versus (void).

Actually I think they are the same, because the rules for composite
types cause the K&R-style definition of main to acquire a prototype.
6.5.2.2p6:

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. If the function is defined with a type that
includes a prototype, [...]

Is main defined with a type that includes a prototype? 6.2.7p4:

For an identifier with internal or external linkage declared in a
scope in which a prior declaration of that identifier is visible, if
the prior declaration specifies internal or external linkage, the type
of the identifier at the later declaration becomes the composite type.

What is the composite type? 6.2.7p3, subitem 2:

If only one type is a function type with a parameter type list (a
function prototype), the composite type is a function prototype with
the parameter type list.

So the K&R-style main() with preceeding prototype should behave
just as though it were defined with a prototype.

Andrey Tarasevich

unread,
Nov 18, 2008, 2:29:12 PM11/18/08
to
Tim Rentsch wrote:
> ...

> Looking at both sides, the explicit statement in 6.7.3p14, especially
> in contrast to the corresponding statement for declarations not part
> of a definition, makes the argument "for" seem a little stronger than
> the argument "against". Is there a crushing counter-argument that
> I'm missing?
> ...

Please, take a look at DR#317

http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_317.htm

It doesn't give a "crushing counter-argument" in terms of a rationale,
but does make the committee's intent clear in rather unambiguous manner.

Harald van Dijk

unread,
Nov 18, 2008, 2:31:08 PM11/18/08
to
On Tue, 18 Nov 2008 10:33:34 -0800, Tim Rentsch wrote:
> Harald van =?UTF-8?b?RMSzaw==?= <tru...@gmail.com> writes:
>> int main(int argc, char *argv[]);
>> int main(argc, argv)
>> int argc;
>> char *argv[];
>> {
>> /* ... */
>> }
>
> Actually I think they are the same, because the rules for composite
> types cause the K&R-style definition of main to acquire a prototype.
[...]
> Is main defined with a type that includes a prototype? 6.2.7p4:
>
> For an identifier with internal or external linkage declared in a
> scope in which a prior declaration of that identifier is visible, if
> the prior declaration specifies internal or external linkage, the
> type of the identifier at the later declaration becomes the
> composite type.

Interesting point. A function definition is an external-declaration, not a
declaration, according to the grammar, so I'm not sure if this applies,
but it's very well possible that you're right.

Keith Thompson

unread,
Nov 18, 2008, 2:57:15 PM11/18/08
to
Tim Rentsch <t...@alumnus.caltech.edu> writes:
> Keith Thompson <ks...@mib.org> writes:
[BIG SNIP]

>>
>> The standard doesn't say that the definition of main must be very
>> similar to "int main(void) { /* ... */ }", differing only in ways that
>> have no effect on the particular program being considered. It says
>> that it must be *equivalent* (or it must follow one of the other two
>> options).
>>
>> In practice, most or all C compilers do support "int main()" with the
>> obvious semantics. If my interpretation is correct (and no, I'm not
>> 100% certain of that), then "int main()", in an implementation that
>> doesn't document it, invokes undefined behavior; [...]
>
> A good argument, and well presented.

Thank you.

> The argument hinges on the function definition
>
> int main(){ return 0; }
>
> not supplying a prototype for main(). Is that in fact the case? I
> would like to give an argument that this definition does in fact
> supply a prototype for main(). First the definition for prototype,
> given in the last sentence of 6.2.1p2:
>
> For each different entity that an identifier designates, the
> identifier is visible (i.e., can be used) only within a region of
> program text called its scope. Different entities designated by the
> same identifier either have different scopes, or are in different
> name spaces. There are four kinds of scopes: function, file, block,
> and function prototype. (A function prototype is a declaration of a
> function that declares the types of its parameters.)
>
> Now a relevant paragraph from the section on function declarators,
> namely 6.7.3p14:

Typo: that's 6.7.5.3p14.

> 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.(126)
>
> Note the second sentence, and contrast it with the third sentence.
> Also, this paragraph being in the section on function /declarators/
> is germane to the argument. The explicit specification that the
> declared function has no parameters means this declaration does
> indeed declare the types of its parameters.

Fascinating. I've always assumed that an empty list was just the
zero-parameter case of a K&R-style non-prototype declaration, but the
above implies that it acts like a "(void)" prototype.

I still suspect that that wasn't the intent. I think what was meant
is that the "()" specifies *for the function definition* that the
function has no parameters. And just as a matter of consistency, I'd
prefer to have a general (implied) rule that any function declaration
that was legal in K&R1 is not a prototype.

But of course we have to go by what the standard actually says.

If your interpretation is correct, then the call to main in this:

int main() { return 0; }
void foo(void) { main(42); }

violates a constraint; I haven't seen a compiler that will diagnose
it.

> The footnote reference (126) says:
>
> 126) See ``future language directions'' (6.11.6).
>
> This section and the one after it merit examination:
>
> 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.
>
> Again, contrast the wording in the two paragraphs. The wording
> identifying "not prototype-format" style is different in the
> case of function definitions, which supports the proposition.

My guess is that the authors just didn't think about the
zero-parameter case, and therefore failed to cover it adequately.

> The opposite side of this argument is (a) 6.11.6 would seem to apply
> to function declarators /in definitions/ in addition to function
> declarations /not/ in definitions, and (b) wording in other places in
> the standard suggests "prototype" is synonymous with there being a
> parameter-type-list.
>
> Looking at both sides, the explicit statement in 6.7.3p14, especially

Again, that's 6.7.5.3p14.

> in contrast to the corresponding statement for declarations not part
> of a definition, makes the argument "for" seem a little stronger than
> the argument "against". Is there a crushing counter-argument that
> I'm missing?
>
> [My apologies if part of this message gets posted twice... editor error]

--

Andrey Tarasevich

unread,
Nov 18, 2008, 3:46:36 PM11/18/08
to
Keith Thompson wrote:
>> This section and the one after it merit examination:
>>
>> 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.
>>
>> Again, contrast the wording in the two paragraphs. The wording
>> identifying "not prototype-format" style is different in the
>> case of function definitions, which supports the proposition.
>
> My guess is that the authors just didn't think about the
> zero-parameter case, and therefore failed to cover it adequately.

As it is stated in the committee response to DR#317, it is actually
covered adequately, although the full logical chain begins at a rather
unexpected point: the key moment here is that according to the _grammar_
the empty '()' stands for an empty _identifier_ list, not for an empty
typed parameter list. And according to this, an empty '()' in the
definition does not include a parameter list and therefore does not
satisfy the definition of a prototype (which happens to require a
parameter list in the function declaration).

Tim Rentsch

unread,
Nov 19, 2008, 8:47:48 AM11/19/08
to

There is 6.7 p 5:

A declaration specifies the interpretation and attributes of a
set of identifiers. A definition of an identifier is a
declaration for that identifier that:

- for an object, causes storage to be reserved for that object;
- for a function, includes the function body;101)
- for an enumeration constant or typedef name, is the (only)
declaration of the identifier.

with 101)

101) Function definitions have a different syntax, described in 6.9.1.

Seems pretty black letter.

Tim Rentsch

unread,
Nov 19, 2008, 9:02:34 AM11/19/08
to
Andrey Tarasevich <andreyta...@hotmail.com> writes:

Well! This DR may not be "crushing", but it is pretty damning to my
argument. :)

I accept that the committee's intent (expressed clearly enough in the
DR) is that an empty argument list in a function definition does not
constitute a prototype. However, their reasoning is bogus. There is
nothing in the standard that ties the term "prototype" to the
syntactic nonterminal "parameter-type-list". A function definition
with an empty argument list satisfies the only statement in the text
that might reasonably be called a definition of "prototype"; in
combination with the previous statement, that makes the argument
that it is a prototype a lot more convincing than the argument
that it isn't a prototype.

May I say, Harrumph!

(And also say thank you Andrey for pointing out the DR.)

Tim Rentsch

unread,
Nov 19, 2008, 9:34:33 AM11/19/08
to
Keith Thompson <ks...@mib.org> writes:

Quite right, thank you for the correction.

> > 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.(126)
> >
> > Note the second sentence, and contrast it with the third sentence.
> > Also, this paragraph being in the section on function /declarators/
> > is germane to the argument. The explicit specification that the
> > declared function has no parameters means this declaration does
> > indeed declare the types of its parameters.
>
> Fascinating. I've always assumed that an empty list was just the
> zero-parameter case of a K&R-style non-prototype declaration, but the
> above implies that it acts like a "(void)" prototype.

Syntactically, it does in fact match the K&R-style syntax rule,
and not the parameter-type-list syntax rule. My argument is
that, whichever syntax rule is involved, an empty parameter list
in a function definition satisfies the definition of "prototype"
and therefore ought to be considered as such.

> I still suspect that that wasn't the intent. I think what was meant
> is that the "()" specifies *for the function definition* that the
> function has no parameters. And just as a matter of consistency, I'd
> prefer to have a general (implied) rule that any function declaration
> that was legal in K&R1 is not a prototype.

Yes, the DR makes clear that it wasn't the intent. Your point about
the function having no parameters brings out a subtle distinction. If
we consider (giving the right section number this time!) 6.7.5.3p5:

If, in the declaration ..T D1.., D1 has the form

D( parameter-type-list )
or

D( identifier-listopt )

and the type specified for ident in the declaration ``T D'' is
``derived-declarator-type-list T'', then the type specified for
ident is ``derived-declarator-type-list function returning T''.

In p14 it's the /function/ that has no parameters, whereas in p5
it's the /type specified for ident/ that has a particular return
type. This distinction, which I hadn't noticed before, weakens
my argument.


> But of course we have to go by what the standard actually says.
>
> If your interpretation is correct, then the call to main in this:
>
> int main() { return 0; }
> void foo(void) { main(42); }
>
> violates a constraint; I haven't seen a compiler that will diagnose
> it.

> [remainder snipped]

Yes, that's a valid conclusion, and it isn't surprising that
compilers don't report it. This gives a slim ray of hope --
if compilers simply started reporting this as an error
(which certainly seems reasonable, since it is guaranteed
UB if ever executed), then the standard committee might be
convinced to let such function definitions serve as prototypes.

Tim Rentsch

unread,
Nov 19, 2008, 9:45:46 AM11/19/08
to
Andrey Tarasevich <andreyta...@hotmail.com> writes:

There is no statement in the standard that says a prototype requires a
parameter list. The only statement that comes close to being a
definition is given inside parentheses in 6.2.1p2:

(A function prototype is a declaration of a function that
declares the types of its parameters.)

A function definition that has no parameters satisfies this
definition - it has no parameters, and it declares the type
of every one of them.

Also, the term "prototype" is never mentioned in conjunction with
either of the nonterminal symbols "parameter-type-list" or
"identifier-list".

Again I say, Harrumph!

Keith Thompson

unread,
Nov 19, 2008, 12:16:44 PM11/19/08
to
Tim Rentsch <t...@alumnus.caltech.edu> writes:
> Andrey Tarasevich <andreyta...@hotmail.com> writes:
[...]

>> As it is stated in the committee response to DR#317, it is actually
>> covered adequately, although the full logical chain begins at a rather
>> unexpected point: the key moment here is that according to the _grammar_
>> the empty '()' stands for an empty _identifier_ list, not for an empty
>> typed parameter list. And according to this, an empty '()' in the
>> definition does not include a parameter list and therefore does not
>> satisfy the definition of a prototype (which happens to require a
>> parameter list in the function declaration).
>
> There is no statement in the standard that says a prototype requires a
> parameter list. The only statement that comes close to being a
> definition is given inside parentheses in 6.2.1p2:
>
> (A function prototype is a declaration of a function that
> declares the types of its parameters.)
>
> A function definition that has no parameters satisfies this
> definition - it has no parameters, and it declares the type
> of every one of them.
>
> Also, the term "prototype" is never mentioned in conjunction with
> either of the nonterminal symbols "parameter-type-list" or
> "identifier-list".
>
> Again I say, Harrumph!

The Committee is making a ruling based on the intent of the authors of
the standard, even though it may contradict the actual wording of the
standard.

They're The Committee. They get to do things like that.

I'm reminded of a ruling by the committee for one of the Algol
standards (60 or 68, I don't remember which), that said something
like

In section such-and-such, the word "is" shall be interpreted to
mean "is not".

In any case, I think that treating a declaration with empty
parentheses as a non-prototype just make more sense (again, even if
the current wording doesn't support that treatment).

I hope that wording in the next version of the standard is revised to
be consistent with the intent.

Nevertheless, I will gladly join you in your response:

Harrumph!

lawrenc...@siemens.com

unread,
Nov 19, 2008, 1:41:13 PM11/19/08
to
Tim Rentsch <t...@alumnus.caltech.edu> wrote:
>
> There is
> nothing in the standard that ties the term "prototype" to the
> syntactic nonterminal "parameter-type-list".

6.2.7p3:

-- If only one type is a function type with a parameter type
list (a function prototype) ...

6.9.1p7:

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.

6.11.7:

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

--
Larry Jones

Buddy, if you think I'm even going to BE here, you're crazy! -- Calvin

lawrenc...@siemens.com

unread,
Nov 19, 2008, 1:47:12 PM11/19/08
to
Tim Rentsch <t...@alumnus.caltech.edu> wrote:
>
> if compilers simply started reporting this as an error
> (which certainly seems reasonable, since it is guaranteed
> UB if ever executed), then the standard committee might be
> convinced to let such function definitions serve as prototypes.

During the C89 deliberations, the committee considered a "Miranda rule"
("You have the right to a prototype. If you cannot afford a prototype,
one will be appointed for you.") that would allow old-style function
definitions to serve as prototypes, but it was reject for fear of
breaking too much old code.
--
Larry Jones

Fortunately, that was our plan from the start. -- Calvin

Tim Rentsch

unread,
Nov 20, 2008, 11:56:00 AM11/20/08
to
lawrenc...@siemens.com writes:

> Tim Rentsch <t...@alumnus.caltech.edu> wrote:
> >
> > There is
> > nothing in the standard that ties the term "prototype" to the
> > syntactic nonterminal "parameter-type-list".
>
> 6.2.7p3:
>
> -- If only one type is a function type with a parameter type
> list (a function prototype) ...
>
> 6.9.1p7:
>
> 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.
>
> 6.11.7:
>
> The use of function declarators with empty parentheses (not
> prototype-format parameter type declarators) is an obsolescent
> feature.

Before my earlier posting I had looked at all of these:

6.2.7p3 looks like a non-restrictive parenthetical remark, not a
definition.

6.9.1p7 says such a declarator /also/ serves as a function prototype;
again, looks more like an additional remark than a definition.

Neither 6.11.6 (which is given above under the numbering 6.11.7) nor
6.11.7 mention the syntactic non-terminal parameter type list.

It's clear that a parameter type list must provide a function
prototype; what isn't clear is that a function prototype requires a
parameter type list. This latter condition is what I meant when I
said "There is nothing in the standard that ties the term 'prototype'
to the syntactic nonterminal 'parameter-type-list'." I believe
that reading of the sentence is still an accurate statement.

To be fair, the comment under "6.11.6 Function Declarators" makes
evident the implication that empty parentheses don't fall under the
heading of prototype. If I'd been a little more alert I would have
realized that this applies to function definitions as well as function
declarations, since function definitions also have function
declarators (but then no one else caught this either). What threw me
off was the apparent dichotomy between 6.11.6 and 6.11.7, seeming to
make separate statements about /declarations/ and /definitions/; for
the sake of clarity, it might be good to combine these two sections
into a single section (titled Function Declarators) with two paragraphs.

Tim Rentsch

unread,
Nov 20, 2008, 12:13:37 PM11/20/08
to
lawrenc...@siemens.com writes:

> Tim Rentsch <t...@alumnus.caltech.edu> wrote:
> >
> > if compilers simply started reporting this as an error
> > (which certainly seems reasonable, since it is guaranteed
> > UB if ever executed), then the standard committee might be
> > convinced to let such function definitions serve as prototypes.
>
> During the C89 deliberations, the committee considered a "Miranda rule"
> ("You have the right to a prototype. If you cannot afford a prototype,
> one will be appointed for you.") that would allow old-style function
> definitions to serve as prototypes, but it was reject for fear of
> breaking too much old code.

Perhaps that was the right decision in 1989. For the particular case
of function definitions that take no parameters, for C201x, the
downside seems pretty small -- any code that supplies any arguments to
such a function is still undefined behavior. There is no change in
semantics, only a requirement that a diagnostic be issued, which could
be satisfied by compilers simply giving a (non-negotiable) warning and
then just going ahead with the compilation.

I understand the reasons for requiring (void) so that a zero-parameter
function declaration supply a prototype. But requiring (void) for a
zero-parameter function /definition/ to be a prototype just seems
wrong.

Keith Thompson

unread,
Nov 20, 2008, 1:13:41 PM11/20/08
to
Tim Rentsch <t...@alumnus.caltech.edu> writes:
[...]

> I understand the reasons for requiring (void) so that a zero-parameter
> function declaration supply a prototype. But requiring (void) for a
> zero-parameter function /definition/ to be a prototype just seems
> wrong.

To me, it seems more wrong to be inconsistent.

C++ took a different route, eliminating non-prototype function
declarations altogether and making () a prototype specifying no
parameters. It would have been nice if C had done the same thing, but
it would have broken backward compatibility.

Non-prototype function declarations are already deprecated in C; see
C99 6.11.6 and 6.11.7. The next standard *could* just eliminate them
altogether and make "void foo(void)" and "void foo()" equivalent
prototypes.

lawrenc...@siemens.com

unread,
Nov 20, 2008, 2:03:41 PM11/20/08
to
Tim Rentsch <t...@alumnus.caltech.edu> wrote:
>
> It's clear that a parameter type list must provide a function
> prototype; what isn't clear is that a function prototype requires a
> parameter type list.

That's because you've been missing the fact that the *only* way to
specify the types of the parameters in a function declaration is by
using a parameter type list. The references I cited, while not
definitional, clearly make that connection.

> What threw me
> off was the apparent dichotomy between 6.11.6 and 6.11.7, seeming to
> make separate statements about /declarations/ and /definitions/; for
> the sake of clarity, it might be good to combine these two sections
> into a single section (titled Function Declarators) with two paragraphs.

Noted.
--
Larry Jones

But Mom, frogs are our FRIENDS! -- Calvin

Tim Rentsch

unread,
Nov 21, 2008, 2:24:24 PM11/21/08
to
lawrenc...@siemens.com writes:

> Tim Rentsch <t...@alumnus.caltech.edu> wrote:
> >
> > It's clear that a parameter type list must provide a function
> > prototype; what isn't clear is that a function prototype requires a
> > parameter type list.
>
> That's because you've been missing the fact that the *only* way to
> specify the types of the parameters in a function declaration is by
> using a parameter type list. The references I cited, while not
> definitional, clearly make that connection.

Apparently my attempt to clarify the meaning of my earlier statement
was unsuccessful. I will try again.

None of the cited references make a direct, explicit statement that
using parameter type lists are the only way to specify the types of a
function's parameters. One makes no reference to parameter type lists
at all; the other two establish that declarations with a parameter
type list serve to provide a prototype (and also supply the types of
the parameters, obviously), but do not say that parameter type lists
are the /only/ way to specify the types of a function's parameters (or
to provide a prototype).

The lack of the word "only" is important, because if there are other
types of declarations that specify a function's parameter types, then
they also provide prototypes. For example, if 6.7.5.3p14 establishes
(as it seems to on first reading) that a function definition with no
parameters specificies a function type with no parameters, then it
also specifies the types of the function's parameters. It turns out
that 6.7.5.3p14 does not establish the number of parameters in the
function's type, but it does seem like it might, and the lack of the
word "only" in other statements about parameter type lists adds
signicantly to the lack of certainty.

I agree that, taking several different sections of the standard and
considering them together, a pretty convincing argument can be made
that only parameter type lists specify the types of function
declaration parameters; however, this result is a consequence of
statements made in fairly wide-ranging sections taken together, not a
statement made directly in the text. It's reasonable to say that the
standard makes this result /evident/, but that's very different from
saying it makes it /clear/. Similarly, the rules of mathematics make
it /evident/ that the equation 'x**N + y**N = z**N' has positive
integer solutions for x, y, z, and N only when N <= 2; but the
truth of this result is far from being clear. I don't have any
problem agreeing that the standard requires prototypes be supplied
only by declarations using a parameter type list; but that
requirement, even though it is present, is not expressed directly
and explicitly enough to expect there won't be some confusion.
The potential for confusion, as evidenced both by the discussion
here and by the person/group who submitted DR#317, makes the
case that language in the standard on this point is not clear.

With all due respect for those who work on defining the standard --
and my respect for them is considerable, for it is a tremendous
achievement, both for what it chooses to say and how it chooses to say
it -- when discussions come up like those that have come up in this
thread (especially when they come up repeatedly), it would be good to
give more consideration to revising or adding a clarifying statement
to make the intended meanings more direct and more explicit. To give
another example, there has been recently and apparently again just now
in another thread, questions raised about whether (char*) arguments
can be passed for (void*) paramters to printf(). Judging by past
postings, the sentiments of the committee are different from the views
of many of the readers here. But the readers here aren't stupid, and
when many smart people reach a "wrong" conclusion, that should send
a fairly strong signal that clarifying language is warranted.

I also want to point out an example on the other side of the fence.
I noticed that the released draft of the C01x standard has new
language for execution sequencing (replacing the old "sequence point"
language). This new language looks like a big improvement over
the old description, which has provoked many a spirited discussion
over the years. So I hope that this is an indication that these
discussions can induce clarifying changes in some cases.

jameskuyper

unread,
Nov 21, 2008, 3:20:31 PM11/21/08
to
Tim Rentsch wrote:
> lawrenc...@siemens.com writes:
>
> > Tim Rentsch <t...@alumnus.caltech.edu> wrote:
> > >
> > > It's clear that a parameter type list must provide a function
> > > prototype; what isn't clear is that a function prototype requires a
> > > parameter type list.
> >
> > That's because you've been missing the fact that the *only* way to
> > specify the types of the parameters in a function declaration is by
> > using a parameter type list. The references I cited, while not
> > definitional, clearly make that connection.
>
> Apparently my attempt to clarify the meaning of my earlier statement
> was unsuccessful. I will try again.
>
> None of the cited references make a direct, explicit statement that
> using parameter type lists are the only way to specify the types of a
> function's parameters. ...

Agreed. There are other ways to specify those types.

> ... One makes no reference to parameter type lists


> at all; the other two establish that declarations with a parameter
> type list serve to provide a prototype (and also supply the types of
> the parameters, obviously), but do not say that parameter type lists
> are the /only/ way to specify the types of a function's parameters

Agreed.

> ... (or to provide a prototype).

That's the key point of the disagreement. In order to qualify as as
prototype, it's not sufficient for the types of a functions parameters
to be specified. 6.2.1p2 says " A function prototype is a declaration
of a function that declares the types of its parameters.". Notice that
key word "declaration". For a K&R style function definition like:

double myfunc(a, b)
int a;
double b;
{ /* Function body */}

the function declaration ends with the ')' on the first line. The part
of the function definition that defines the parameter types is on the
next two lines, which are not part of the function declaration.

When there is no parameter declaration list, it is not the function
declaration itself that defines the fact that the function takes no
parameters; it is the combination of the function declaration and the
fact that it is immediately followed by a function body which conveys
that information.

Proving that this is true with citations from the standard is a little
tedious, because the standard does not directly define the term
"function declaration". It defines what a declaration is, and what a
function definition is. Some declarations declare functions, and the
first part of a function definition always qualifies as a declaration,
but the standard doesn't say directly that this IS a function
declaration, so it gets a bit messy.

Section 6.7p1 says:
> declaration:
> declaration-specifiers init-declarator-listopt ;
...
> init-declarator-list:
> init-declarator
> init-declarator-list , init-declarator
>
> init-declarator:
> declarator
> declarator = initializer


Section 6.7.5p1 says:
> declarator:
> pointeropt direct-declarator
>
> direct-declarator:
...
> direct-declarator ( identifier-listopt )

Section 6.9.1p1 says:
> function-definition:
> declaration-specifiers declarator declaration-listopt compound-statement

The first part of a K&R function definition can be parsed as a
declaration where the init-declarator-list consists of exactly one
init-declarator. The init-declarator is a single declarator with no
initializer. The declarator is a direct declarator of the type that
ends with (identifier-listopt). Therefore, the "declaration-
specifiers declarator" part of a K&R-style function declaration
constitutes a complete declaration in itself, and if you follow the
grammar closely, you'll see that there's no way for the declaration to
continue past the end of the ')' that ends the declarator. It would
have to have a ',' after it in order for the declaration to continue,
and if you put in that ',', it's no longer a function definition. The
parameter declaration list is it's own set of object declarations,
rather than being part of the function declaration.

Tim Rentsch

unread,
Nov 22, 2008, 8:28:30 AM11/22/08
to
jameskuyper <james...@verizon.net> writes:

To make a long story short, I agree with the conclusion but not
with the reasoning. A function definition is all a declaration,
by 6.7p5,

A declaration specifies the interpretation and attributes of a
set of identifiers. A definition of an identifier is a
declaration for that identifier that:

- for an object, causes storage to be reserved for that object;
- for a function, includes the function body;

- for an enumeration constant or typedef name, is the (only)
declaration of the identifier.

So the function body is included in the declaration. However, that's
a moot point, for a different reason. In other sections that refer to
prototypes, they talk about functions that have "_a type_ that
includes a prototype" (my emphasis). So even though a K&R function
definition/declaration specifies the types of its parameters, the
associated type that results does /not/ have any of that information.
A function definition with an empty parameter list specifies a
function that takes no parameters, but the type produced by that
definition has no information about how many parameters it takes (or
the types of same).

0 new messages