Re: (part 21) Han from China answers your C questions



Keith Thompson <kst-u@xxxxxxx> writes:

Tim Rentsch <txr@xxxxxxxxxxxxxxxxxxx> writes:
Keith Thompson <kst-u@xxxxxxx> 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.

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.
.



Relevant Pages

  • compiling ibcs on Debian 3.0 / 2.4.19 kernel and on Debian 2.2r5 / 2.2.26 kernel
    ... warning: this is the location of the previous ... declaration isn't a prototype ... incompatible pointer type ...
    (Debian-User)
  • Re: [SLE] compile problem -- WebCam
    ... > the archive and issue the make command. ... > declaration isn't a prototype ... > definition has no type or storage class ...
    (SuSE)
  • Re: General question
    ... declaration for, it assumed that it was a function returning an int ... The first true C standard, ANSI/ISO of 1989 and 1990, changed things. ... Its prototype is: ...
    (comp.lang.c)
  • Re: Some Questions #2
    ... "if expr1 and expr2 are expressions, ... a byte is defined as synonymous with a char. ... A declaration describes the type of object or function ... A prototype is a description of a function's parameters. ...
    (comp.lang.c)
  • call of variadic function
    ... Consider the variadic function with the following prototype: ... Here 'num' specifies the number of arguments, ... arguments that should be passed to this function are of type int. ... Assuming that the prototype is visible in the scope of the function ...
    (comp.lang.c)