Was it always like that?

M

Melzzzzz

I am really puzzled that I have to
return from main.
main.c:
int main(void)
{
}

bmaxa@maxa:~/examples$ gcc -Wall main.c
main.c: In function ‘main’:
main.c:3:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
bmaxa@maxa:~/examples$ clang -Wall main.c
bmaxa@maxa:~/examples$ icc -Wall main.c
bmaxa@maxa:~/examples$

Of three C compilers that I use, only gcc gives warning. What does
it means? Is it something new or was always like that?
 
B

Ben Bacarisse

Melzzzzz said:
I am really puzzled that I have to
return from main.
main.c:
int main(void)
{
}

bmaxa@maxa:~/examples$ gcc -Wall main.c
main.c: In function ‘main’:
main.c:3:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^

You don't have to have an explicit return in C99 (and C11). Add, say,
-std=c99 and (for my version of gcc) the warning goes away.
bmaxa@maxa:~/examples$ clang -Wall main.c
bmaxa@maxa:~/examples$ icc -Wall main.c
bmaxa@maxa:~/examples$

Of three C compilers that I use, only gcc gives warning. What does
it means?

It's just a choice that various compiler authors made. I'd prefer to
told about a missing return when compiling ANSI C, but clang and icc
chose not to do that. All compilers I tests correctly warn about
missing return statements in other non-void functions, but main is a
little different.
Is it something new or was always like that?

Pass.
 
J

James Kuyper

I am really puzzled that I have to
return from main.

You don't have to. Either main() a any subroutine thereof can enter an
infinitely loop, or call any _Noreturn function, and that would not be
problem (at least, not in itself - if done in the wrong context, it
could cause other problems). The C standard library provides six
_Noreturn functions: longjmp() (which doesn't really count for this
purpose, since it just transfers control to some other part of the
code), abort(), exit(), _Exit(), quick_exit(), and thrd_exit(), and
people are allowed to define similar functions of their own.
main.c:
int main(void)
{
}

The above is not an example of failing to return from main(). There is
an implicit return when execution of a program reaches the end of a
function, which in this case happens immediately at the start of the
program.
bmaxa@maxa:~/examples$ gcc -Wall main.c
main.c: In function ‘main’:
main.c:3:1: warning: control reaches end of non-void function [-Wreturn-type]
}

The problem isn't a failure to return from main; your code does that.
It's failing to provide a return value. main() is declared as returning
an int value, and you've failed to provide one for it to return. Even
that's not necessarily a problem: failing to provide a return value only
has undefined behavior if the calling routine tries to use the return
value that you failed to provide (6.9.1p12). I hope you can understand
why that would be a problem?
There's also a special exemption even from that rule, for main():
reaching the end of main() without returning a value is implicitly
equivalent to "return 0;" (5.1.2.2.3p1).

That's why this is merely a warning, and not an error message. It is a
bad idea to take advantage of the special exemption for main(), and
dangerous to rely upon the exemption for return values that aren't used.
A function that isn't supposed to be returning a value should be
declared void. That return type isn't under your control for main(), so
you should always return some value when exiting main(). However, in
this particular case the behavior is well-defined.
Of three C compilers that I use, only gcc gives warning. What does
it means? Is it something new or was always like that?

The only relevant rule that has changed is the special exemption for
main(), which was added in C99. Before that, failing to return a value
from main() had undefined behavior, because the caller to main() might
(and almost certainly would) try to use the return value you had failed
to provide.
 
K

Keith Thompson

James Kuyper said:
I am really puzzled that I have to
return from main.

You don't have to. Either main() a any subroutine thereof can enter an
infinitely loop, or call any _Noreturn function, and that would not be
problem (at least, not in itself - if done in the wrong context, it
could cause other problems). The C standard library provides six
_Noreturn functions: longjmp() (which doesn't really count for this
purpose, since it just transfers control to some other part of the
code), abort(), exit(), _Exit(), quick_exit(), and thrd_exit(), and
people are allowed to define similar functions of their own.
main.c:
int main(void)
{
}

The above is not an example of failing to return from main(). There is
an implicit return when execution of a program reaches the end of a
function, which in this case happens immediately at the start of the
program.
bmaxa@maxa:~/examples$ gcc -Wall main.c
main.c: In function ‘main’:
main.c:3:1: warning: control reaches end of non-void function [-Wreturn-type]
}

The problem isn't a failure to return from main; your code does that.
It's failing to provide a return value. main() is declared as returning
an int value, and you've failed to provide one for it to return. Even
that's not necessarily a problem: failing to provide a return value only
has undefined behavior if the calling routine tries to use the return
value that you failed to provide (6.9.1p12). I hope you can understand
why that would be a problem?
There's also a special exemption even from that rule, for main():
reaching the end of main() without returning a value is implicitly
equivalent to "return 0;" (5.1.2.2.3p1).

That's why this is merely a warning, and not an error message.

No, that's not why it's a warning.

gcc by default is equivalent to "gcc -std=gnu89", which corresponds to
1989 ANSI C with GNU extensions. In that dialect of C, reaching the
closing "}" of main() returns an undefined status to the environment,
and that's what gcc is warning about. (In fact when I compile and run
"int main(void){}" with default options, it generally does return a
non-zero status.)

"gcc -std=c99" or later does not issue the warning, and it generates
different code that returns a status of 0.
 
K

Kenny McCormack

Keith Thompson said:
"gcc -std=c99" or later does not issue the warning, and it generates
different code that returns a status of 0.

The defacto standard (prior to c99) was that if you didn't code an explicit
"return" statement, then the return value (of just about any non-void
function, not just main()) was the value most recently evaluated by the
function. Yes, I know this wasn't a "standard" in the sense used by the
religion of CLC; that's why I called it a "defacto" standard.

This means that: int main(void) { puts("hello, world"); }
would result in a return status of 13.

Incidentally, int main(void) { puts("hello, world");20; }
should result in a return status of 20, but modern compilers are too smart
to be fooled by that... (Even with no optimization requested)

--
"I heard somebody say, 'Where's Nelson Mandela?' Well,
Mandela's dead. Because Saddam killed all the Mandelas."

George W. Bush, on the former South African president who
is still very much alive, Sept. 20, 2007
 
G

glen herrmannsfeldt

Ben Bacarisse said:
I am really puzzled that I have to
return from main.
main.c:
int main(void)
{
}
bmaxa@maxa:~/examples$ gcc -Wall main.c
main.c: In function ???main???:
main.c:3:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
(snip)

It's just a choice that various compiler authors made. I'd prefer to
told about a missing return when compiling ANSI C, but clang and icc
chose not to do that. All compilers I tests correctly warn about
missing return statements in other non-void functions, but main is a
little different.
Is it something new or was always like that?

Well, before ANSI C, and so before void, functions were declared
int if there was no other need for a type, and so would often not
have a return statement.

My K&R1 isn't handy, but I thought that it returned 0 in that case.

Many calling conventions put int return values in a specific register.
If the compiler doesn't load something, you get whatever happens to be
in that register.

-- glen
 
K

Keith Thompson

glen herrmannsfeldt said:
Well, before ANSI C, and so before void, functions were declared
int if there was no other need for a type, and so would often not
have a return statement.

My K&R1 isn't handy, but I thought that it returned 0 in that case.

The pre-ANSI convention was to omit the return type (letting it
default to int) for a function that doesn't return a value.

Either executing a "return;" statement (with no expression) or falling
off the end of a function would return an undefined value to the caller.

If the caller doesn't attempt to use the value, there was no problem.
Many calling conventions put int return values in a specific register.
If the compiler doesn't load something, you get whatever happens to be
in that register.

Right.
 
J

Joe Pfeiffer

The defacto standard (prior to c99) was that if you didn't code an explicit
"return" statement, then the return value (of just about any non-void
function, not just main()) was the value most recently evaluated by the
function. Yes, I know this wasn't a "standard" in the sense used by the
religion of CLC; that's why I called it a "defacto" standard.

Not on all platforms, and only by luck. In particular...

I once made exactly this mistake (forgetting to return the result
calculated) in a program originally meant for x86. As that value was
indeed the last thing calculated, it happened to still be in the EAX
register, which is used for function returns in that architecture.

When the code was recompiled for SPARC, the value wound up in a register
other than the one that was used for function returns. Ooops...
 
K

Kenny McCormack

Not by "luck" at all.

(Thinking back to the old Hee Haw cornfield routine - with the tag line "If
it weren't for bad luck, I'd have no luck at all")

If it weren't for snarky, over-the-top, hyperbolic posts in CLC, we'd have
no posts at all.

(Yes, I'm looking at you, Joe)
 
J

Joe Pfeiffer

(Thinking back to the old Hee Haw cornfield routine - with the tag line "If
it weren't for bad luck, I'd have no luck at all")

If it weren't for snarky, over-the-top, hyperbolic posts in CLC, we'd have
no posts at all.

(Yes, I'm looking at you, Joe)

If giving a specific example of a compiler on a major vendor's platform
which doesn't follow your "de facto standard" is snarky, over-the-top,
and hyperbolic then I'm all three. I suppose quoting the 1975 C
reference manual saying "Flowing off the end of a function is equivalent
to a return with no returned value" (on page 14) would be equally
over-the-top and hyperbolic.
 
K

Kaz Kylheku

Not on all platforms, and only by luck. In particular...

I once made exactly this mistake (forgetting to return the result
calculated) in a program originally meant for x86. As that value was
indeed the last thing calculated, it happened to still be in the EAX
register, which is used for function returns in that architecture.

When the code was recompiled for SPARC, the value wound up in a register
other than the one that was used for function returns. Ooops...

So SPARC is weird and doesn't "conform" to Kenny's "de facto" standard.

That could be related to the reason why we don't see SPARC-based chips in
cellphones, tablests, or anywhere else, really.

If they only had propagated the return value of a puts out of main
with no return statement, things might be different today. :)
 
J

James Kuyper

On Mon, 17 Feb 2014 09:30:32 -0500 in comp.lang.c, James Kuyper


Really? It seems like the exemption is there exactly to be taken
advantage of. Why else would there be an exception?

Of course it was put there to be taken advantage of. That doesn't mean
it was a good decision to put it there, nor that it's a good idea to
take advantage of the fact that it was put there.

My only objection to people using "void main()" is the fact that the
standard doesn't guarantee that it is supported. I don't favor adding
"void main()" as signature that implementations are required to support,
but neither am I opposed to it. If the committee wanted to cater to
those who don't want to be bothered returning a value from main(), then
it should have allowed this only if main() is declared as returning void.

Having a function declared as returning a value, where use of that value
to determine the exit status returned to the host environment is
mandated by the standard, and then allowing it to return without
specifying a return value, was just plain wrong.
 
K

Kaz Kylheku

Of course it was put there to be taken advantage of.

The implicit successful return from main was probably not put there to be taken
advantage of. It was probably put there to fix the misbehaving termination
status of legacy programs which do that, and which are never going to be
fixed with a "return 0", but which might be recompiled with C99.

This was a poor idea in itself; changing the behavior of unknown amounts of
code. As Kenny observed, programs out there may be relying (whether
by intent or accident) on the behavior that the return value of an int function
in the tail position of main is propagated.

(And if you're going to cave in to poor programming, why not "bless"
void main also while you're at it ...)
 
A

alpha

I am really puzzled that I have to
return from main.
main.c:
int main(void)
{
}

bmaxa@maxa:~/examples$ gcc -Wall main.c
main.c: In function 'main':
main.c:3:1: warning: control reaches end of non-void function
[-Wreturn-type]
}
^
bmaxa@maxa:~/examples$ clang -Wall main.c
bmaxa@maxa:~/examples$ icc -Wall main.c
bmaxa@maxa:~/examples$

Of three C compilers that I use, only gcc gives warning. What does
it means? Is it something new or was always like that?

--
Click OK to continue...


Isnt the short and simple answer that main() declared to return an integer
value is missing
said return value in the brackets ? For example {return 0;} would fix the
warning.
Since the other 2 compiler dont return a warning the authors must have
followed
a different standard. Just my 2 cents
 
J

James Kuyper

On 02/21/2014 12:52 AM, Robert Wessel wrote:
....
In general, reaching the end of a function* returning a value has
always been undefined if the caller attempts to use that value.

main() has always had a special dispensation. In C89 the return was
defined to work, although the value returned to the OS is undefined.

Can you cite the text that provides a special dispensation for main() in
C89? I don't have a copy of that standard, but my understanding is that
there was no such special dispensation until C99.
 
K

Kenny McCormack

On 02/21/2014 12:52 AM, Robert Wessel wrote:
...

Can you cite the text that provides a special dispensation for main() in
C89? I don't have a copy of that standard, but my understanding is that
there was no such special dispensation until C99.

Heh heh. And you claim that clc is not motivated by the same sorts of
impulses as motivate religion...?

--
Here's a simple test for Fox viewers:

1) Sit back, close your eyes, and think (Yes, I know that's hard for you).
2) Think about and imagine all of your ridiculous fantasies about Barack Obama.
3) Now, imagine that he is white. Cogitate on how absurd your fantasies
seem now.

See? That wasn't hard, was it?
 
B

Ben Bacarisse

James Kuyper said:
On 02/21/2014 12:52 AM, Robert Wessel wrote:
...

Can you cite the text that provides a special dispensation for main() in
C89? I don't have a copy of that standard, but my understanding is that
there was no such special dispensation until C99.

"If the main function executes a return that specifies no value, the
termination status returned to the host environment is undefined."

Right at the end on 2.1.2.2
http://www.bsb.me.uk/ansi-c/ansi-c-one-file.html#sec_2_1_2_2
 
S

Seebs

"If the main function executes a return that specifies no value, the
termination status returned to the host environment is undefined."

I *think*, although I'm not sure, that the reason Something Had To Be Done
is that this doesn't make any sense; *behavior* can be undefined, but a
termination status... well, that's weird, what can it be? It could be
unspecified, probably, but it may be that you want to indicate that
something could go horribly wrong, in which case you'd be saying that the
behavior was undefined. But that seems undesireable, and no one knows of
an implementation which actually explodes.

My memory's sort of vague, it's been >15 years now.

-s
 
K

Kaz Kylheku

I *think*, although I'm not sure, that the reason Something Had To Be Done
is that this doesn't make any sense; *behavior* can be undefined, but a
termination status... well, that's weird, what can it be?

The obvious fix is "the termination status is indeterminate", regarding it
as a kind of value that the program can produce, but which doesn't
have a C type, being an abstraction with the domain values "successful",
"failed" and possibly other.
It could be unspecified, probably, but it may be that you want to indicate that

If it's unspecified, then there has to be some set of alternatives from
among which the implementation makes an undocumented choice.
something could go horribly wrong, in which case you'd be saying that the
behavior was undefined.

Undefined behavior isn't only "something could go horribly wrong".

Undefined behavior is also such stuff as including <unistd.h> or calling fcntl.

Undefined behavior upon main falling out without a return value is fine;
implementors could work at detecting the situation, and convert it to
a successful status, as an extension. (The same way they have to since C99,
to provide required behavior.)
But that seems undesireable, and no one knows of
an implementation which actually explodes.

Many implementations also do not explode when an int-returning function
that neglects to return anything is called, and its return value is retrieved.

In many of those implementation which don't explode when main neglects
to return a value, main is actually returning to some other function, and
not directly to the OS. So that isn't blowing up either.

Also, many implementations do not explode when the blasphemous void main is
used, the recognition of whose undefinedness is a rite of passage around
here.
 

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,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top