exit() values and the C standards?

Z

Zach

Hi,

I'm trying to get a handle on the various values that may be used with
exit(). I've come across 2 differing definitions:

"The C standard specifies two constants, EXIT_SUCCESS and
EXIT_FAILURE,
that may be passed to exit() to indicate successful or
unsuccessful
termination, respectively."

and

"The C Standard () defines the values 0, EXIT_SUCCESS, and
EXIT_FAILURE."

Does one of these definitions apply to the C90 standard and the other
to C99?
Or do both standards only define the constants EXIT_SUCCESS and
EXIT_FAILURE and most compiler implementations associate 0 with
EXIT_SUCCESS and 1 with EXIT_FAILURE? Which standard should I follow
in general practice?

Also, I've seen in code other values such as:
exit(3);

What do these other values (besides 0 and 1) indicate specifically and
which should I use to have good, portable C code?

Regards,
Zach
 
B

Ben Pfaff

[semantics of argument to the exit function]
Or do both standards only define the constants EXIT_SUCCESS and
EXIT_FAILURE and most compiler implementations associate 0 with
EXIT_SUCCESS and 1 with EXIT_FAILURE? Which standard should I follow
in general practice?

Both C89 and C99 have the same wording in this area:

If the value of status is zero or EXIT_SUCCESS, an
implementation-defined form of the status successful
termination is returned. If the value of status is
EXIT_FAILURE, an implementation-defined form of the status
unsuccessful termination is returned. Otherwise the status
returned is implementation-defined.

My guess is that 0 for EXIT_SUCCESS and 1 for EXIT_FAILURE is
most common. POSIX requires that EXIT_SUCCESS be 0 (but only
requires that EXIT_FAILURE be nonzero, not that it be 1).
Also, I've seen in code other values such as:
exit(3);

What do these other values (besides 0 and 1) indicate specifically and
which should I use to have good, portable C code?

The meaning of other status values is implementation defined. I
would use one of the standard exit codes in portable C code.
 
C

Chris Riesbeck

Zach said:
Hi,

I'm trying to get a handle on the various values that may be used with
exit(). I've come across 2 differing definitions:

"The C standard specifies two constants, EXIT_SUCCESS and
EXIT_FAILURE,
that may be passed to exit() to indicate successful or
unsuccessful
termination, respectively."

and

"The C Standard () defines the values 0, EXIT_SUCCESS, and
EXIT_FAILURE."

Does one of these definitions apply to the C90 standard and the other
to C99?

My copy of the 1999 C standard says "If the value of status is zero or
EXIT_SUCCESS, ... If the value of status is EXIT_FAILURE, ..."
 
Z

Zach

I'd be interested to see the statistics supporting your "most".

Hi,

I was not making an assertion, I meant that as an interrogative.
ISO/IEC 9899. Which flavour depends on how portable you need to be
and how up to date your vendor is.

When I compile in gcc I use -std=c99.
 
C

CBFalconer

Richard said:
Zach said:
.... snip ...


Then you need to be aware of the places where gcc departs from the
C99 Standard. See http://gcc.gnu.org/c99status.html for details.

In addition you are making your code non-portable to C90 systems.
So I suggest that you only use that when you actually need to use
some C99 features. Otherwise C90 (or -ansi) is quite sufficient.
You should also use -W -Wall -pedantic.

In general anything that meets C90 requirements will meed C99
requirements. The reverse is not true. Also, C99 will reject some
things accepted by C90, which are bad practice, such as using the
default int typing.
 
J

jameskuyper

CBFalconer said:
In addition you are making your code non-portable to C90 systems.
So I suggest that you only use that when you actually need to use
some C99 features.

I would give slightly different advice: use C99 features freely,
except when your code really needs to be able to compile with a
compiler that won't support them. Complain about compilers when they
don't support a feature you want to use. If someone decides to mandate
use of a compiler that doesn't support those features, when there is
also a compiler available that does support them, complain about that,
too.

With the widespread availability of compilers like gcc that support
most of the new C99 features, I think that the need to be able to
compile on systems where those features are not supported has become
less common than you are assuming it to be.
 
Z

Zach

Therefore, any stats you hear about "most implementations"
are almost certain to be illusory.

Thanks for the caveat. I recall using this old implementation of C on
an AT&T Unix PC (tm) my Dad had. It had a pretty decent C Trainer that
came with it.
Then you need to be aware of the places where gcc departs from the
C99 Standard. Seehttp://gcc.gnu.org/c99status.htmlfor details.

This is very helpful, thank you.

Zach
 
Z

Zach

In addition you are making your code non-portable to C90 systems.
So I suggest that you only use that when you actually need to use
some C99 features. Otherwise C90 (or -ansi) is quite sufficient.
You should also use -W -Wall -pedantic.

In general anything that meets C90 requirements will meed C99
requirements. The reverse is not true. Also, C99 will reject some
things accepted by C90, which are bad practice, such as using the
default int typing.

Oh, I see. Thank you Chuck.

Zach
 
R

Richard

CBFalconer said:
In addition you are making your code non-portable to C90 systems.
So I suggest that you only use that when you actually need to use
some C99 features. Otherwise C90 (or -ansi) is quite sufficient.
You should also use -W -Wall -pedantic.

In general anything that meets C90 requirements will meed C99
requirements. The reverse is not true. Also, C99 will reject some
things accepted by C90, which are bad practice, such as using the
default int typing.

Ridiculous advice.

Should one maybe look further back for ancient compilers which do not
confirm to C90?

Use the features of the language as it develops. Unless you KNOW you are
tar getting antiquated or static systems which do not move with the
times.

You'll be recommending Pascal next.
 
G

Guest

I would give slightly different advice: use C99 features freely,
except when your code really needs to be able to compile with a
compiler that won't support them.

strongly disagree. I like my code to be close to maximally
ported. I've seen too many projects that were "never going to be
ported" and then were. C99 is *still* not available widely enough
to ensure portability.

Treat C99 features like any other extension. Avoid it
unless you *really* need it and then isolate it in
as small a number of modules as possible. Tag it in both
the code and the documentation.

Complain about compilers when they
don't support a feature you want to use. If someone decides to mandate
use of a compiler that doesn't support those features, when there is
also a compiler available that does support them, complain about that,
too.

With the widespread availability of compilers like gcc that support
most of the new C99 features, I think that the need to be able to
compile on systems where those features are not supported has become
less common than you are assuming it to be.

even gcc isn't fully compliant and there is plenty that
has even less support.
 
J

James Kuyper

strongly disagree. I like my code to be close to maximally
ported. I've seen too many projects that were "never going to be
ported" and then were. ...

But it's not unreasonable, in my opinion, to assume that a given piece
of code is unlikely to be ported to any given platform until after that
platform has at least one compiler which supports all the C99 features
the program depends upon, even though no such compiler is available now.

None of the programs I'm responsible for would be noticeably less useful
if I restricted their portability by using C99 features, so long as I
restricted myself to using only those C99 features that are fully
supported by gcc.

We're contractually obligated to deliver code that complies with C90,
but that's not because of any objections on the part of the client to
C99. It's simply because the contract was negotiated before C99 even
existed, and there's insufficient motivation to justify renegotiating
its terms.

....
even gcc isn't fully compliant and there is plenty that
has even less support.

If we wait until C99 is fully supported on a wide variety of platforms
before making any significant use of any of it's features, we'll never
create any significant pressure for implementors to provide fully
conforming implementations, and they will never come into existence.
Acting as though it will never happen will virtually ensure that it
never happens. Someone has to pull C implementors into the 21st century,
and I'm willing to bear my fair share of the burden of doing that pulling.
 
R

Richard

strongly disagree. I like my code to be close to maximally
ported. I've seen too many projects that were "never going to be

I wonder what maximally ported means in this case.

I also wonder just how much of your code is "ported".
ported" and then were. C99 is *still* not available widely enough
to ensure portability.

Treat C99 features like any other extension. Avoid it
unless you *really* need it and then isolate it in
as small a number of modules as possible. Tag it in both
the code and the documentation.

With that mentality nothing would ever progress.
 
G

Guest

I wonder what maximally ported means in this case.

a typo for maximally portable. Though that's pretty much
a hand wavey term. As portable as possible I suppose.
And yes, I know I'm not going to port IBM mainframe code
to a toaster.
I also wonder just how much of your code is "ported".

well when I say "my" code. I mean code I have been associated with.

N: HP-UX -> Windows

M: embedded system been ported across several generations of h/w

I've seen things break when moving between machines from the same
manufacturer.
 
B

Brian Inglis

I'd be interested to see the statistics supporting your "most".

A couple of exception examples:

Digital VMS stdlib.h defined EXIT_SUCCESS as 0 and EXIT_FAILURE as 2,
and zero was converted to 1 at the OS interface.
VMS considered odd numbers successful, failures unsuccessful, and
displayed an error message indexed by the OS code.
The generic OS codes and messages were 1 and 2.

Many IBM mainframe environments used OS codes in multiples of 4 as
severity levels: 4 was a warning, 8 was a problem, 12 was serious, can't
remember if higher was defined; the mapping probably varied by compiler
vendor and environment, and I don't remember any of them now.
I would expect EXIT_FAILURE, likely to be 1 or the actual value, to
produce the most severe OS code, to guarantee a failure was taken
seriously.
I would also expect implementation defined values to allow reporting the
other OS codes.
 
K

Keith Thompson

Brian Inglis said:
A couple of exception examples:

Digital VMS stdlib.h defined EXIT_SUCCESS as 0 and EXIT_FAILURE as 2,
and zero was converted to 1 at the OS interface.
VMS considered odd numbers successful, failures unsuccessful, and
displayed an error message indexed by the OS code.
The generic OS codes and messages were 1 and 2.

Interesting. Earlier in this thread, Larry Jones wrote that Vax 11 C
defined EXIT_SUCCESS with a value other than 0.

I know there were (are, I suppose) two major C compilers for VAX/VMS,
the older VAXC and the newer DECC (the latter works for both VAX and
Alpha systems). Perhaps their associated headers define EXIT_SUCCESS
differently?
 
E

Eric Sosman

Keith said:
Interesting. Earlier in this thread, Larry Jones wrote that Vax 11 C
defined EXIT_SUCCESS with a value other than 0.

I know there were (are, I suppose) two major C compilers for VAX/VMS,
the older VAXC and the newer DECC (the latter works for both VAX and
Alpha systems). Perhaps their associated headers define EXIT_SUCCESS
differently?

My recollection is hazy (it's been many years), but I don't
think VAXC defined EXIT_SUCCESS at all. I don't think it even
had a <stdlib.h> header -- remember, <stdlib.h> was one of those
headers that was purely an invention of the ANSI committee, not
a codification of prior art, and the pre-Standard VAXC wouldn't
have had it.

DEC decided to leave VAXC more or less as it was rather than
to try to force it into the new Standard's mold, presumably for
fear of disrupting existing code. Instead, they brought out DECC
as a Standard-compliant (modulo bugs) compiler, complete with its
own headers and run-time library. Alas, I do not recall the numeric
value of DECC's EXIT_SUCCESS; our own code was also pre-Standard and
used its own macros and conventions to deal with different systems'
notions of "success" and "failure."
 
K

Keith Thompson

Eric Sosman said:
My recollection is hazy (it's been many years), but I don't
think VAXC defined EXIT_SUCCESS at all. I don't think it even
had a <stdlib.h> header -- remember, <stdlib.h> was one of those
headers that was purely an invention of the ANSI committee, not
a codification of prior art, and the pre-Standard VAXC wouldn't
have had it.

DEC decided to leave VAXC more or less as it was rather than
to try to force it into the new Standard's mold, presumably for
fear of disrupting existing code. Instead, they brought out DECC
as a Standard-compliant (modulo bugs) compiler, complete with its
own headers and run-time library. Alas, I do not recall the numeric
value of DECC's EXIT_SUCCESS; our own code was also pre-Standard and
used its own macros and conventions to deal with different systems'
notions of "success" and "failure."

VAXC is pretty old, but I don't *think* DEC left it entirely stagnant.
At a previous job around 1998, we had code that we could compile with
either VAXC or DECC; most of it used prototypes, so VAXC (unless I'm
misremembering) couldn't have been *entirely* pre-ANSI.

It did have some interesting quirks. For example, old versions of C
(before even K&R1) reversed the order of the compound assignment
operators, so that "x =- y;" meant "x = x - y;". If you typed:
x=-1;
VAXC was smart enough to warn you about the ambiguity (in K&R and
later versions of C, it means "x = -1;") -- but would then go ahead
and interpret it as an "=-" operator.

Anyway, I managed to find a VMS demo system and ran the following
program on it:

#include <stdlib.h>
#include <stdio.h>
int main(void)
{
printf("EXIT_SUCCESS = %d\n", EXIT_SUCCESS);
printf("EXIT_FAILURE = %d\n", EXIT_FAILURE);
return 0;
}

Using DECC, the output was:

EXIT_SUCCESS = 0
EXIT_FAILURE = 268435458

where 268435458 == 0x10000002, so we at least have a concrete example
where EXIT_FAILURE != 1. The system doesn't have VAXC installed.
 
K

Keith Thompson

Eric Sosman said:
Keith said:
Eric Sosman said:
[...]
My recollection is hazy (it's been many years), but I don't
think VAXC defined EXIT_SUCCESS at all. I don't think it even
had a <stdlib.h> header -- remember, <stdlib.h> was one of those
headers that was purely an invention of the ANSI committee, not
a codification of prior art, and the pre-Standard VAXC wouldn't
have had it.

DEC decided to leave VAXC more or less as it was rather than
to try to force it into the new Standard's mold, presumably for
fear of disrupting existing code. Instead, they brought out DECC
as a Standard-compliant (modulo bugs) compiler, complete with its
own headers and run-time library. Alas, I do not recall the numeric
value of DECC's EXIT_SUCCESS; our own code was also pre-Standard and
used its own macros and conventions to deal with different systems'
notions of "success" and "failure."
VAXC is pretty old, but I don't *think* DEC left it entirely
stagnant.
At a previous job around 1998, we had code that we could compile with
either VAXC or DECC; most of it used prototypes, so VAXC (unless I'm
misremembering) couldn't have been *entirely* pre-ANSI.

I wrote "more or less as it was," which isn't the same as saying
"entirely stagnant." VAXC never promised to love, honor, and obey
the upstart Standard, but did make a few polite nods in its direction
when they seemed unlikely to break existing VAXC code. A few of the
Standard-invented headers were introduced eventually, but they didn't
(couldn't) always contain exactly what the Standard dictated -- the
idea was to aid in writing code that could be both pre- and post-
Standard.

VAXC was a pre-ANSI compiler that acquired a few ANSIisms by
virtue of not dying out the moment the Standard appeared.

That sounds about right.
That doesn't square with my recollection -- but as I mentioned
before, my recollection isn't entirely trustworthy. Although VAXC
was pre-ANSI it pretty much couldn't have been pre-K&R; I believe the
warning was there but that the interpretation remained K&R's. I'm
sure I would have had a LOT more porting problems had VAXC used the
already-obsolete-in-1978 semantics.

My recollection (which I suspect will turn out to be consistent with
yours) is that the warning and pre-K&R interpretation were triggered
only in cases that would have been ambiguous in pre-K&R C. If you
wrote "x=-1;" you got the warning, and it was interpreted as if you
had written the more modern "x -= 1;". If there was a space between
the '=' and the '-': "x = -1;", then there was no problem. If your
source code wasn't written with a fanatical hatred of whitespace, you
might not have run into this issue.
[...]
Using DECC, the output was:
EXIT_SUCCESS = 0
EXIT_FAILURE = 268435458
where 268435458 == 0x10000002, so we at least have a concrete example
where EXIT_FAILURE != 1. The system doesn't have VAXC installed.

Even if it did, VAXC's partial and gradual accomodation to the
Standard may well have meant that EXIT_FAILURE had different values
(or no value) in different VAXC versions.

Quite possibly. What I'm really curious about, though, is whether
(some version of) VAXC uses a value other than 0 for EXIT_SUCCESS.
 
L

Larry Gates

Does one of these definitions apply to the C90 standard and the other
to C99?
Or do both standards only define the constants EXIT_SUCCESS and
EXIT_FAILURE and most compiler implementations associate 0 with
EXIT_SUCCESS and 1 with EXIT_FAILURE?

EXIT_SUCCESS and EXIT_FAILURE have been around for as long as I've been
studying C. I'd bet long odds they're in both standards.
Which standard should I follow in general practice?

That's a normative question, and I hope you realize that your norms are
your own. For me the answer is C99. I have no significant body of legacy
code and am looking forward to possibilities with interop. People's
notions of what "portability" is differ. I like to think I can pull out
the source I write today ten or twenty years from now and can have it
compile. YMMV.

I keep routines around from fortran 77. They are portable in the other
time direction. BTW, I return one and zero routinely and have never been
bit by it.
 
J

Jasen Betts

Also, I've seen in code other values such as:
exit(3);

What do these other values (besides 0 and 1) indicate specifically and
which should I use to have good, portable C code?

you get implementation defined behavior.


In windows or dos the exit value winds up in ERRORLEVEL.
In unix it's pretty-much the same but the return value
isn't called errorlevel.
 

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,995
Messages
2,570,236
Members
46,822
Latest member
israfaceZa

Latest Threads

Top