Is "int main() { }" strictly conforming?

  • Thread starter Johannes Schaub (litb)
  • Start date
J

Johannes Schaub (litb)

The spec says it can be defined as

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

or

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

or equivalent. Or in some implementation-defined manner (not strictly
conforming anymore).

Because "int main() { }" is not equivalent to "int main(void) { }", I take
it that "int main() { }" is not supported for strictly conforming programs?
 
K

Keith Thompson

Johannes Schaub (litb) said:
The spec says it can be defined as

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

or

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

or equivalent. Or in some implementation-defined manner (not strictly
conforming anymore).

Because "int main() { }" is not equivalent to "int main(void) { }", I take
it that "int main() { }" is not supported for strictly conforming programs?

I agree.

If the implementation documents that "int main()" is permitted,
then a program that uses it is well-behaved, with its behavior
defined by the implementation.

Otherwise, such a program's behavior is undefined.

In practice, the actual behavior for "int main()" is almost certain to
be the same as "int main(void)".
 
L

lawrence.jones

In comp.std.c "Johannes Schaub (litb) said:
Because "int main() { }" is not equivalent to "int main(void) { }", I take
it that "int main() { }" is not supported for strictly conforming programs?

They're not equivalent as declarations because one acts as a prototype and
the other doesn't, but they are equivalent as definitions (they both
define main as a function taking no arguments). I'm sure the committee
indended to allow both for strictly conforming programs, but one could
argue that the standard doesn't actually say that (and Keith Thompson
[forgive me if I've misspelled your name, Keith] probably will, if he
hasn't already).
 
D

David R Tribble

Keith said:
In practice, the actual behavior for "int main()" is almost certain to
be the same as "int main(void)".

Here's a related question, since I'm not as adept at ISO C
as I once was...

Given a function definition of:
int main() { ... }
does the standard state that this is substantially different
from:
int main(void) { ... }

My point of view is that since main() receives no arguments,
including any varargs, how can it have any calling linkage
different than 'main(void)'?
 
J

Johannes Schaub (litb)

David said:
Here's a related question, since I'm not as adept at ISO C
as I once was...

Given a function definition of:
int main() { ... }
does the standard state that this is substantially different
from:
int main(void) { ... }

My point of view is that since main() receives no arguments,
including any varargs, how can it have any calling linkage
different than 'main(void)'?

The key here is the meaning of "substantially different". The spec requires
no diagnostic for

int main() {
main("lulz");
}

I prefer to get errors in my code if I do a mistake, so I would consider
this a substantial difference.
 
J

jacob navia

Le 11/03/11 16:29, Johannes Schaub (litb) a écrit :
The spec says it can be defined as

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

or

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

or equivalent. Or in some implementation-defined manner (not strictly
conforming anymore).

Because "int main() { }" is not equivalent to "int main(void) { }", I take
it that "int main() { }" is not supported for strictly conforming programs?

Can't we move this discussion to comp.std.c???

We have discussed this here a zillion times already.

Yes, and we should not cast the result of malloc. Yes I know.
BUT PLEEEEEEEZE....
 
T

Tim Rentsch

Johannes Schaub (litb) said:
The spec says it can be defined as

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

or

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

or equivalent. Or in some implementation-defined manner (not strictly
conforming anymore).

Because "int main() { }" is not equivalent to "int main(void) { }", I take
it that "int main() { }" is not supported for strictly conforming programs?

will respond in comp.std.c.
 
J

James Kuyper

Section 6.91, footnote 137, has examples which show
that two function definitions like those above,
are compatible.

typedef int F(void); // type F is ��function with no parameters
// returning int��

int f(void) { /* ... */ } // RIGHT: f has type compatible with F
int g() { /* ... */ } // RIGHT: g has type compatible with F

The key point is that the requirement specified by the standard is that
any alternatives be "equivalent" to the specified forms, not
"compatible" with them. Unlike "compatible", the standard provide no
specific definition of "equivalent" that applies in this context. The
closest it comes is footnote 9, which lists a couple of ways in which
the declaration can be different while remaining equivalent. Those
examples neither clearly include nor clearly exclude this case. The
Rationale does not address this issue either.

However, the fact that it did not use the word "compatible", even though
the word was available and well-defined, implies that "compatible" would
not have conveyed the intent of that passage.
 
H

Harald van Dijk

However, the fact that it did not use the word "compatible", even though
the word was available and well-defined, implies that "compatible" would
not have conveyed the intent of that passage.

enum compatible_with_int_1 { please=-1, dont, let };
enum compatible_with_int_2 { this=-1, be, valid };

/* whether the enums are compatible with int is implementation-
defined. */

int check_compatibility_1;
enum compatible_with_int_1 check_compatibility_1;

int check_compatibility_2;
enum compatible_with_int_2 check_compatibility_2;

/* if they are not, a diagnostic will be generated for the above
lines.
but on my system, they are compatible. */

enum compatible_with_int_1 main(void) {
int (*p)(void) = main;
return 0;
}

This definition of main is compatible with but not equivalent to int
main(void): unlike int main(void), it is incompatible with enum
compatible_with_int_2 main(void). And unlike the int main() case,
there is no possible way to argue that this is "equivalent as a
definition only".
 
K

Keith Thompson

Harald van Dijk said:
enum compatible_with_int_1 { please=-1, dont, let };
enum compatible_with_int_2 { this=-1, be, valid };

/* whether the enums are compatible with int is implementation-
defined. */

int check_compatibility_1;
enum compatible_with_int_1 check_compatibility_1;

int check_compatibility_2;
enum compatible_with_int_2 check_compatibility_2;

/* if they are not, a diagnostic will be generated for the above
lines.
but on my system, they are compatible. */

enum compatible_with_int_1 main(void) {
int (*p)(void) = main;
return 0;
}

This definition of main is compatible with but not equivalent to int
main(void): unlike int main(void), it is incompatible with enum
compatible_with_int_2 main(void). And unlike the int main() case,
there is no possible way to argue that this is "equivalent as a
definition only".

I'd say that 5.1.2.2.1p1 doesn't permit this *unless* the
implemetation documents it as "some other implementation-defined
manner".

If it is, then 5.1.2.2.3 applies; since the return type is compatible
with int, the status returned to the host environment is defined.

If the implementation permits "long main(void)", then 5.1.2.2.3
doesn't apply, and the status returned to the host environment is
undefined (unless the implementation defines it, which it certainly
should). (Note that int and long are not compatible even if they
happen to have the same representation.)
 
D

David Thompson

Aside: that's 6.9.1.
True; but int g() is also compatible with int h(int x, double y).
Function compatibility is much weaker for K&R1-style function
declarations, including definitions functioning(!) as declarations.
See 6.7.5.3p16 for details, although not much explanation.
So 'compatible' can't be, and per below isn't, the criterion used.

Useless aside: pete's newsreader (which identifies as Mozilla 3) used
Microsoft's nonstandard 'smart' quotes 0x91 and 0x92 but asserted
charset=iso-8859-1, and yours (ditto Mozilla 5) properly but
unhelpfully munged to UTF-8 U+FFFD Replacement.
I can't check what's actually in the Standard here, only what Adobe
Reader gives me, and I trust that as far as I can throw it.
The key point is that the requirement specified by the standard is that
any alternatives be "equivalent" to the specified forms, not
"compatible" with them. Unlike "compatible", the standard provide no
specific definition of "equivalent" that applies in this context. The
closest it comes is footnote 9, which lists a couple of ways in which
the declaration can be different while remaining equivalent. Those
examples neither clearly include nor clearly exclude this case. The
Rationale does not address this issue either.
Yes the documents don't clearly say so, but J11 must have intended to
allow K&R1-style for both 0-arg and 2-arg forms. As Tim Rentsch says,
in 1999 there was still a lot of K&R1-style code, and C99 retains
K&R1-style declaration and definition even though C89 had labelled
them obsolescent (and C99 still does). Even further, C89 didn't have
the wording "or equivalent (footnote 9)" yet in 1989 ALL existing code
was K&R1, and J11's mandate, secondary only to getting a standard at
all, was to preserve existing (K&R1) code.
 

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,744
Messages
2,569,483
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top