newbie question on understanding the main() function

S

some

If i write main like the following ways. Which one will compile and
why?

1. char * main();
2. char * main(int, char);
3. char * main(char);

I guess only first will(but, all three will flag a warning from the
compiler) because main in C needs argument names(not just argument
types) and cannot take a single argument(either zero or two
arguments). I tried this with GNU C compiler 4.3.2 on a Debian Linux
2.6.26.

I am a newbie so would appreciate any feedback if my understanding and
reasoning is correct.

Thanks
 
I

Ian Collins

some said:
If i write main like the following ways. Which one will compile and
why?

1. char * main();
2. char * main(int, char);
3. char * main(char);

I guess only first will(but, all three will flag a warning from the
compiler) because main in C needs argument names(not just argument
types) and cannot take a single argument(either zero or two
arguments). I tried this with GNU C compiler 4.3.2 on a Debian Linux
2.6.26.

The first may compile, but on a hosted implementation such as yours main
returns int, not char*
 
S

Seebs

If i write main like the following ways. Which one will compile and
why?

Possibly none.
1. char * main();
2. char * main(int, char);
3. char * main(char);
I guess only first will(but, all three will flag a warning from the
compiler) because main in C needs argument names(not just argument
types) and cannot take a single argument(either zero or two
arguments). I tried this with GNU C compiler 4.3.2 on a Debian Linux
2.6.26.

You don't need argument names in a declaration, only in a definition;
since it ends with a semicolon, this is just a declaration. On the
other hand, you've declared the second argument with the wrong type.

However, the compiler is free to flag this declaration as incorrect,
because it knows that main() returns int.

-s
 
S

Stefan Ram

some said:
If i write main like the following ways. Which one will compile and
why?

This should be implementation-defined (»5.1.2.2.1 Program startup«:
»or in some other implementation-defined manner«). So, all these are
not maximally portable among conforming implementations. Every
implementation must accept

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

or

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

, so these are recommended.
 
E

Eric Sosman

If i write main like the following ways. Which one will compile and
why?

1. char * main();
2. char * main(int, char);
3. char * main(char);

I guess only first will(but, all three will flag a warning from the
compiler) because main in C needs argument names(not just argument
types) and cannot take a single argument(either zero or two
arguments). I tried this with GNU C compiler 4.3.2 on a Debian Linux
2.6.26.

All are likely to compile, because all are legal -- in a
free-standing program, where main() has no special significance.

In a hosted environment, though, all three are wrong. They
are likely to compile, but they are wrong nonetheless.
I am a newbie so would appreciate any feedback if my understanding and
reasoning is correct.

I can't tell about your understanding. Your reasoning, though,
is incorrect: "C needs argument names (not just argument types)" is
true for function definitions, but the three lines you've shown are
function declarations, *not* definitions. Right or wrong, all are
legal as declarations.
 
S

some

Thanks to all who responded to my question.

Richard said:
They are all wrong, but the compiler is not required to diagnose any of
them. This is one of those cases where the compiler is allowed to expect
you to know what you're doing;

How do I know which cases are such(where compiler will not flag an
error, but actually
legal so don't evoke an error message from compiler)? I realize cases
where I am
allocating/deallocating memory, doing pointer arithmetic, returning
address of a local
variable from a function are cases where compiler will not balk as
they are legal, but are
wrong?

Which book should I read to know about such cases?
 
S

some

Eric said:
All are likely to compile, because all are legal -- in a
free-standing program, where main() has no special significance.

How do I identify which code is legal(meaning compiler will not
produce any errors)? I thought all three were illegal, but was proved
wrong by the compiler.
In a hosted environment, though, all three are wrong. They
are likely to compile, but they are wrong nonetheless.


I can't tell about your understanding. Your reasoning, though,
is incorrect: "C needs argument names (not just argument types)" is
true for function definitions, but the three lines you've shown are
function declarations, *not* definitions. Right or wrong, all are
legal as declarations.

Thanks for the clarification.
 
S

santosh

some wrote:
How do I know which cases are such(where compiler will not flag an error, but actually legal so don't evoke an
error message from compiler)? I realize cases where I am allocating/deallocating memory, doing pointer arithmetic,
returning address of a local variable from a function are cases where compiler will not balk as they are legal, but
are wrong?

Which book should I read to know about such cases?

Since you claim to be a beginner, rather than trying to figure the
Standard, I'd recommend you to pick up a copy of The C Programming
Language 2nd Ed. by Kernighan & Ritchie. It's lucid, authoritative and
fairly comprehensive from the POV of the C90 standard. It's also
suitable as a "first book" to learn C from.

One other often recommended book would be C: A Reference Manual by
Harbison & Steele. It's meant to comprehensively cover the latest
version of Standard C, but it's not suitable for learning C from.

<http://cm.bell-labs.com/cm/cs/cbook/>
<http://www.careferencemanual.com/>
 
P

Phred Phungus

Richard said:
They are all wrong, but the compiler is not required to diagnose any of
them. This is one of those cases where the compiler is allowed to expect
you to know what you're doing; in such cases, if you /don't/ know what
you're doing, that's your problem, not the compiler's.

Note that the absence of argument names is not a problem because the
above are declarations, not definitions.


You're sure that the compiler isn't bothered by the lack of the ** in char?

I would think that these would traouble:

int main(int, char);
int main(char);
 
P

Philip Potter

Thanks to all who responded to my question.



How do I know which cases are such(where compiler will not flag an
error, but actually
legal so don't evoke an error message from compiler)? I realize cases
where I am
allocating/deallocating memory, doing pointer arithmetic, returning
address of a local
variable from a function are cases where compiler will not balk as
they are legal, but are
wrong?

Which book should I read to know about such cases?

A good starting place would be to read through the comp.lang.c FAQ at
http://c-faq.com/. There's a lot of discussion of different types of
not-well-defined-but-not-necessarily-error-producing code there to get
you started; particularly the sections on expressions, pointers and
memory allocation, but elsewhere too.

However, while it is a good resource, it is not enough on its own; it
must be read *in addition* to a good textbook such as those recommended
by santosh.

Also, if you haven't done so already, you should find out how to turn on
your compiler's stricter error checking modes. You mentioned you were
using gcc, so try:

gcc -ansi -pedantic -Wall -Wextra -o<destination> <source>

-ansi turns off extensions which are not allowed by the Standard
-pedantic emits all diagnostics (warnings) required by the Standard
-Wall turns on lots more warnings
-Wextra turns on even more warnings [can use -W instead of -Wextra]

In this case, -Wall enables the -Wmain warning:
-Wmain
Warn if the type of main is suspicious. main should be a function
with external linkage, returning int, taking either zero arguments,
two, or three arguments of appropriate types. This warning is
enabled by -Wall.

[If you're interested, the three-argument main() mentioned is a
nonstandard extension which (I think) provides a pointer to a data
structure representing the environment. Rather than using this
extension, you can just use the (standard, porable) getenv() function
instead.]

Phil
 
S

santosh

Philip said:
On 08/02/2010 03:46, some wrote: [...]
How do I know which cases are such(where compiler will not flag an error, but actually legal so don't evoke
an error message from compiler)? I realize cases where I am allocating/deallocating memory, doing pointer
arithmetic, returning address of a local variable from a function are cases where compiler will not balk as they
are legal, but are wrong?

Which book should I read to know about such cases?

A good starting place would be to read through the comp.lang.c FAQ at
http://c-faq.com/. There's a lot of discussion of different types of
not-well-defined-but-not-necessarily-error-producing code there to get
you started; particularly the sections on expressions, pointers and
memory allocation, but elsewhere too.

However, while it is a good resource, it is not enough on its own; it
must be read *in addition* to a good textbook such as those recommended
by santosh.

Also, if you haven't done so already, you should find out how to turn on
your compiler's stricter error checking modes. You mentioned you were
using gcc, so try:

gcc -ansi -pedantic -Wall -Wextra -o<destination> <source>

-ansi turns off extensions which are not allowed by the Standard
-pedantic emits all diagnostics (warnings) required by the Standard
-Wall turns on lots more warnings
-Wextra turns on even more warnings [can use -W instead of -Wextra]

In this case, -Wall enables the -Wmain warning:
-Wmain
Warn if the type of main is suspicious. main should be a function
with external linkage, returning int, taking either zero arguments,
two, or three arguments of appropriate types. This warning is
enabled by -Wall.

[If you're interested, the three-argument main() mentioned is a
nonstandard extension which (I think) provides a pointer to a data
structure representing the environment. Rather than using this
extension, you can just use the (standard, porable) getenv() function
instead.]

I would also suggest turning on the switch[es] for optimisations
during compiling. The analysis the compiler does for optimisation
often points out many suspicious constructs like unusued/uninitialised
variables, dead code and so on, which might be of interest to those
learning to program. Look for the 'O' switch, or a variant, under most
compilers.
 
B

Ben Bacarisse

some said:
How do I identify which code is legal(meaning compiler will not
produce any errors)? I thought all three were illegal, but was proved
wrong by the compiler.

It is not very useful to define legal/illegal in terms of what message
you get from a compiler. For one thing, different compiler options
can produce wildly differing quantities of diagnostics from the same
code. For another, the standard does not require an implementation to
"produce errors". All it does is list some things that must give rise
to "a diagnostic" while at the same time permitting any other
diagnostics that the implementation may like to produce.

The closest you can get to what you describe is to avoid all those
errors that are described as "constraint violations" by the standard.
These must be diagnosed by the compiler. An incorrect definition of
main is not a constraint violation (I am not sure why, but there it
is) so the compiler can be silent about it if it chooses to be.

<snip>
 
E

Eric Sosman

How do I identify which code is legal(meaning compiler will not
produce any errors)? I thought all three were illegal, but was proved
wrong by the compiler.

The compiler cannot decree what is "legal" and "illegal,"
because in most jurisdictions the compiler does not have the
force of law. The compiler cannot fine you, throw you in jail,
or lop off your right hand on account of any code you might
put before it.

That's a bit silly, of course, but it's intended to make a
more serious point: The definition of C is not written with
"thou shalt" and "thou shalt not," but more along the lines of
a contract or agreement: "If thou dost X, the implementation
shall respond as Y."

There are two parties to this contract, and each must keep
up his side of the bargain for the agreement to have meaning.
Your choices of X are restricted to things that the agreement
covers: If you do X' instead, where X' is not part of the agreed
universe of possibilities, the implementation is no longer bound
to keep up its side of the agreement you've abrogated.

Some kinds of out-of-bounds X' require the implementation to
issue a diagnostic message. The implementation may then reject
the program altogether, or may accept it and try to run it anyhow.
(Even if it runs, though, the agreement has been violated and no
longer governs what the program might do.) Some other kinds of
invalid X' produce "undefined behavior," meaning that they may
or may not elicit diagnostics, and they may or may not do what
you hoped they would. ABSENCE OF DIAGNOSTICS IS NOT CORRECTNESS.

To the point at hand: In a hosted environment, part of your
side of the agreement is to provide a main() function in one of
two prescribed styles. Your main() can take no arguments, or it
can take one int and one char** argument; in both cases, it must
be defined as returning an int value. If you fail to provide a
main(), or if you provide a main() of some other flavor, you have
provided an X' and the agreement no longer holds. The compiler
may complain and reject your code, or may complain and accept it,
or may accept it in silence -- but in the latter cases, C itself
does not define what your program may or may not do.
 
P

Philip Potter

An incorrect definition of
main is not a constraint violation (I am not sure why, but there it
is) so the compiler can be silent about it if it chooses to be.

One reason might be that implementations are free to allow alternative
definitions of main() other than int main(void) and int main(int,
char**). For example, the fairly widely used
int main(int argc, char **argv, char **envp)
would violate any constraint requiring main to be one of the two
standard prototypes.

I don't know how old envp is. I used it once or twice in the 90s in
Turbo C. If it is old enough to be pre-Standard, it may have influenced
the Committee not to make a reasonably common extension a constraint
violation.

Phil
 
B

Ben Bacarisse

Philip Potter said:
One reason might be that implementations are free to allow alternative
definitions of main() other than int main(void) and int main(int,
char**). For example, the fairly widely used
int main(int argc, char **argv, char **envp)
would violate any constraint requiring main to be one of the two
standard prototypes.

I'd have thought that the wording could permit implementation-defined
alternatives (without a diagnostic) but I take your point.

Another way would be to do what is done with constant expressions --
extensions are allowed but anything that is not a constant expression
as defined by the standard must be diagnosed. Helpful when writing
for portability.

It hardly matters. main can appear only once so it is one of the
simplest things to check when moving from one system to another.
I don't know how old envp is. I used it once or twice in the 90s in
Turbo C. If it is old enough to be pre-Standard, it may have influenced
the Committee not to make a reasonably common extension a constraint
violation.

It is certainly pre-standard. Of course, pre-standard it was usually
written main(argc, argv, envp) int argc; char **argv, **evnp; {...}

So many changes happened in the C90 standard that I doubt an extra
diagnostic would be considered much trouble but that is a largely
unfounded opinion!
 
S

Seebs

One reason might be that implementations are free to allow alternative
definitions of main() other than int main(void) and int main(int,
char**). For example, the fairly widely used
int main(int argc, char **argv, char **envp)
would violate any constraint requiring main to be one of the two
standard prototypes.

When I submitted my hack to gcc to warn for incorrect main, I made that
one a pedantic warning rather than a regular warning. The reason is that
it predaces the standard by a LONG margin... But is considered
obsolescent.
I don't know how old envp is. I used it once or twice in the 90s in
Turbo C. If it is old enough to be pre-Standard, it may have influenced
the Committee not to make a reasonably common extension a constraint
violation.

That may be. Meanwhile, the POSIX folks went ahead and standardized
"extern char **environ;" as a superior replacement. ("Superior" is a
matter of potential dispute, I guess.)

-s
 
S

some

Thanks to all who responded.

Philip said:
Thanks to all who responded to my question.



How do I know which cases are such(where compiler will not flag an
error, but actually
legal so don't evoke an error message from compiler)? I realize cases
where I am
allocating/deallocating memory, doing pointer arithmetic, returning
address of a local
variable from a function are cases where compiler will not balk as
they are legal, but are
wrong?

Which book should I read to know about such cases?

A good starting place would be to read through the comp.lang.c FAQ at
http://c-faq.com/. There's a lot of discussion of different types of
not-well-defined-but-not-necessarily-error-producing code there to get
you started; particularly the sections on expressions, pointers and
memory allocation, but elsewhere too.

However, while it is a good resource, it is not enough on its own; it
must be read *in addition* to a good textbook such as those recommended
by santosh.

Also, if you haven't done so already, you should find out how to turn on
your compiler's stricter error checking modes. You mentioned you were
using gcc, so try:

gcc -ansi -pedantic -Wall -Wextra -o<destination> <source>

-ansi turns off extensions which are not allowed by the Standard
-pedantic emits all diagnostics (warnings) required by the Standard
-Wall turns on lots more warnings
-Wextra turns on even more warnings [can use -W instead of -Wextra]

In this case, -Wall enables the -Wmain warning:
-Wmain
Warn if the type of main is suspicious. main should be a function
with external linkage, returning int, taking either zero arguments,
two, or three arguments of appropriate types. This warning is
enabled by -Wall.

I will turn on the warnings as you suggest and use lint if it
is available on my system to catch such mistakes which are legal
but lead to undefined behavior.

I will also go through the Standard, K&R
and Harrison Steele's Reference manual. The Harrison Steele's C
Reference manual
book looks more difficult to understand than the K&R
and the examples at the end of each chapter are certainly tougher for
me than K&R.
Perhaps, I am too dense as I hear high school students and college
freshmen solve them easily
I need some sharpening of wits.

Thanks again to all who responded.
 
T

Tim Rentsch

Ben Bacarisse said:
Philip Potter said:
One reason might be that implementations are free to allow alternative
definitions of main() other than int main(void) and int main(int,
char**). For example, the fairly widely used
int main(int argc, char **argv, char **envp)
would violate any constraint requiring main to be one of the two
standard prototypes.

I'd have thought that the wording could permit implementation-defined
alternatives (without a diagnostic) but I take your point.

Another way would be to do what is done with constant expressions --
extensions are allowed but anything that is not a constant expression
as defined by the standard must be diagnosed. [snip]

As far as I know implementation-specific constant expressions are
not required to be given a diagnostic (assuming 6.6p3 isn't
violated), since 6.6p10 explicitly and specifically allows them
as constant expressions. Do have a supporting citation? No
constraints are violated as far as I know.
 
B

Ben Bacarisse

Tim Rentsch said:
Ben Bacarisse <[email protected]> writes:
Another way would be to do what is done with constant expressions --
extensions are allowed but anything that is not a constant expression
as defined by the standard must be diagnosed. [snip]

As far as I know implementation-specific constant expressions are
not required to be given a diagnostic (assuming 6.6p3 isn't
violated), since 6.6p10 explicitly and specifically allows them
as constant expressions. Do have a supporting citation?

No. I was miss-remembering something, though I don't know what exactly.
 

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

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,045
Latest member
DRCM

Latest Threads

Top