Clunky C cleanup code

K

Keith Thompson

dandelion said:
It makes the main() return value portable. On Un*x 0 is used to indicate
successful program termination and any non-zero value is (commonly)
interpreted as success (disclaimer: there are a few programs that do not
obey this rule, IIRC).

On other platforms it may be different and a successfull program termination
may be required to return 1, 0xDEADBEEF or anything else. Using
EXIT_SUCCESS, this problem is taken care of (portably) by the header files.

The EXIT_SUCCESS and EXIT_FAILURE macros were introduced in C89 to
allow a portable way for a program to indicate success or failure. In
my opinion, the way it was done was only half a solution.

In Unix, traditionally 0 denotes success, and any non-zero value (most
commonly 1) denotes failure. Other systems have different
conventions. In particular, on VMS 0 (or any even value) denotes
failure, and 1 (or any odd value) denotes success. In ISO C, 0 is
required to indicate success, and EXIT_SUCCESS and EXIT_FAILURE
indicate success and failure, respectively. There's seldom any reason
for EXIT_SUCCESS to have a value other than 0, but it's allowed to do
so.

A better solution, IMHO, would have been to make any value other than
EXIT_SUCCESS or EXIT_FAILURE non-portable. As it is, the standard
made programs that use exit(1) non-portable, but decreed that exit(0)
would continue to be portable, causing a minor implementation headache
for VMS. The result is uglier than it needed to be.
 
M

Michael Mair

Keith said:
Returning __LINE__ from the main program is non-portable. On some
systems, only the low-order 8 bits are used, so a return from line 256
would indicate success. More generally, returning any value other
than 0, EXIT_SUCCESS, or EXIT_FAILURE from main() is non-portable.

Thanks for clarifying this -- I was aware of it but referred (not
quite clearly, I fear) to the rest of integer-returning functions :)

As for using __LINE__ to show where the error occurred, that's not a
bad idea, but it's useful only if the person seeing the error message
has access to (the current version of) the source. It's a debugging
tool for developers, not a way to produce error messages that are
going to be meaningful to an end user. (Note that the assert() macro
does this.)

True enough. But I've seen the "Huh? What? Where am I?" version
of error messages often enough to appreciate being able to
report to the developer the file and line together with the
setting in which it went wrong instead of being able to just
pass along that there was an error which made the program puke...
However, I really was not very clear above and just threw about
a couple of ideas: Thank you for elaborating :)


Cheers
Michael
 
D

dandelion

Flash Gordon said:
Incorrect. The C standard defines that returning 0 from main or using
exit(0) causes the implementation to return an implementation defined
value indicating success to the environment.


Such programs are IMHO brocken.

The '0' was referring to the value required by posix, not the definition of
EXIT_SUCCESS.
In which case the implementation has to handle that.

Which it can easily do. Main, after all, is a mere C-function, called by
OS-dependent
startup-code. It's return value can easily be evaluated into any other
value.
Just like it has to handle 0 correctly when it is used in a pointer context even if the null
pointer is not all bits zero.

Which sometimes results in 'too much pain' to quote one of the excellent
articles posted here recently.
See above. 0 indicates success whatever the OS requires. Failure, on the
other hand, can only poitably be indicated using EXIT_FAILURE.

From a standards perspective you are absolutely correct, of course, however,
counting on EXIT_FAILURE to be returned on abnormal program termination is
naive.

Apart from that, this is one of those cases where I would gladly sacrifice
some 'portability' for functionality. Especially if the software is intended
(or expected) to be used in (say) unix shell-scripts.

Porting main return values isn't exactly rocket science. In this case,
IMHO, the OS requirements are more important than the language requirements.
The C-Standard (or any other language standard for that matter) is not the
holy grail in application development. Important, sure, but there are other
important considerations aswell.

The sources I have (notably http://www-ccs.ucsd.edu/c/stdlib.html#exit) also
tell me

<quote>
exit
void exit(int status);

The function calls all functions registered by atexit, closes all files, and
returns control to the target environment. If status is zero or
EXIT_SUCCESS, the program reports successful termination. If status is
EXIT_FAILURE, the program reports unsuccessful termination. An
implementation can define additional values for status.

</quote>

Hence EXIT_FAILURE does not seem to have an exclusive status.
 
A

Al Bowers

Al said:
char *clean_string(const char * string, const char * chop)
{
char *tmp, *final;
size_t count;
const size_t CHUNK = 16;

for(final = NULL, count = 0;*string != '\0' ; string++)
{
if(count%CHUNK == 0)
{
tmp = realloc(final,count+CHUNK+1);
if(tmp == NULL)
{
free(final);
return NULL;
}
final = tmp;
}
if(strchr(chop,*string)) continue;
final[count++] = *string;
}
final[count] = '\0';

I think you mean:
if(final) final[count] = '\0';
 
F

Flash Gordon

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The '0' was referring to the value required by posix, not the
definition of EXIT_SUCCESS.

Yes, and I meant that any *nix programs the return either 0 on failure
of non-zero on success are brocken.
Which it can easily do. Main, after all, is a mere C-function, called
by OS-dependent
startup-code. It's return value can easily be evaluated into any other
value.

Yes, I know exactly how it works.
Which sometimes results in 'too much pain' to quote one of the
excellent articles posted here recently.

What is the pain for the programmer in returning 0 for success? In
another post Keith raises valid points about the pain it causes the
person writing the implementation.
From a standards perspective you are absolutely correct, of course,
however, counting on EXIT_FAILURE to be returned on abnormal program
termination is naive.

I did not say that you can assume other programs are written correctly,
I only said that when *you* write a program if you want it to be
portable you have to use one of 0, EXIT_SUCCESS or EXIT_FAILURE with the
first two indicating success.

The question asked by MPJ was "Q) Is there any virtue to using
EXIT_SUCCESS as opposed to 0 ?" to which you replied "It makes the
main() return value portable." Returning EXIT_SUCCESS instead of 0 has
absolutely no impact on portability.
Apart from that, this is one of those cases where I would gladly
sacrifice some 'portability' for functionality. Especially if the
software is intended(or expected) to be used in (say) unix
shell-scripts.

Yes, and I do use non-portable return values from main when I consider
it appropriate. However, this has no impact on whether or not 0 is a
portable values since the standard defines that it is.
Porting main return values isn't exactly rocket science. In this
case, IMHO, the OS requirements are more important than the language
requirements. The C-Standard (or any other language standard for that
matter) is not the holy grail in application development. Important,
sure, but there are other important considerations aswell.

I don't disagree with that. Had your post not at least implied that 0
was non-portable I probably would not have replied to you at all.
The sources I have (notably
http://www-ccs.ucsd.edu/c/stdlib.html#exit) also tell me

<quote>
exit
void exit(int status);

The function calls all functions registered by atexit, closes all
files, and returns control to the target environment. If status is
zero or EXIT_SUCCESS, the program reports successful termination. If
status is EXIT_FAILURE, the program reports unsuccessful termination.
An implementation can define additional values for status.

</quote>

Hence EXIT_FAILURE does not seem to have an exclusive status.

EXIT_FAILURE is the *only* value you can return and know that it will
indicate a failure on all systems. That is it's exclusive state. A
system where 9274 was the only integer value that indicated failure
(with EXIT_FAILURE defined as 9274) would be perfectly conforming.
 
M

Michael Wojcik

True, but it did contain a function declaration inside main(). This is
legal, but rarely advisable.

And even then only if the function isn't defined with the static
storage-class specifier (ie as having internal linkage). A function
declaration at block scope cannot have any sc-specifier other than
extern. See C90 6.1.2.2 and 6.5.1. This means that you can't
correctly declare a static function at block scope.

While a block-scope function declaration might seem like a nice idea
for restricting the visibility of the function name, perhaps to let
the implementation verify which blocks may invoke a given function
(so the declaration becomes part of the function contract, in a
sense), in practice it's not really useful, even if it were supported
for internal-linkage functions.

--
Michael Wojcik (e-mail address removed)

Q: What is the derivation and meaning of the name Erwin?
A: It is English from the Anglo-Saxon and means Tariff Act of 1909.
-- Columbus (Ohio) Citizen
 
M

Michael Wojcik

That leaves little room for failure. :)
Such programs are IMHO brocken.

You may, of course, have your opinion, but I think diff, for example,
has excellent reasons for its choice of exit values (0 for no
differences found, 1 for differences found, 2 for failure - the
comparison couldn't be made). Of course this is not portable, but
it is useful for those implementations that diff was written to.
There's no other mechanism in Unix that diff might use to convey
these three values so conveniently to its invoker.

--
Michael Wojcik (e-mail address removed)

O sometimes, nevertheless,
The labourer at his instrument or tractor,
Bending into a state of merge with objects,
Finds the same love that, from a machine of sex,
Steps down as Venus to her invoker. -- George Barker
 
F

Flash Gordon

On 2 Dec 2004 21:42:18 GMT
That leaves little room for failure. :)


You may, of course, have your opinion, but I think diff, for example,
has excellent reasons for its choice of exit values (0 for no
differences found, 1 for differences found, 2 for failure - the
comparison couldn't be made). Of course this is not portable, but
it is useful for those implementations that diff was written to.
There's no other mechanism in Unix that diff might use to convey
these three values so conveniently to its invoker.

OK, I'll grant that in some circumstances it is reasonable. I've never
been one to stick to a position when presented with good
evidence/argument to the contrary.
 
T

Tim Rentsch

Flash Gordon said:
I've never been one to stick to a position when presented
with good evidence/argument to the contrary.

Wow. How do you ever expect to fit in in this NG?

:)
 
D

dandelion

^^^^^^^
Should have read 'failure' of course.
The '0' was referring to the value required by posix, not the
definition of EXIT_SUCCESS.

Yes, and I meant that any *nix programs the return either 0 on failure
of non-zero on success are brocken.

Ah.... I misunderstood. Apologies. Btw. This is the second time you spell
'broken' as 'brocken'. I'm not nagging you about typo's (I hate that
myself), but in this case i'm wondering wether there is any special
intention to it (since you seem to spell it that way consistently).

What is the pain for the programmer in returning 0 for success?

The non-zero null-pointer, not the zero 'success' value.
In another post Keith raises valid points about the pain it causes the
person writing the implementation.


I did not say that you can assume other programs are written correctly,
I only said that when *you* write a program if you want it to be
portable you have to use one of 0, EXIT_SUCCESS or EXIT_FAILURE with the
first two indicating success.

The question asked by MPJ was "Q) Is there any virtue to using
EXIT_SUCCESS as opposed to 0 ?" to which you replied "It makes the
main() return value portable." Returning EXIT_SUCCESS instead of 0 has
absolutely no impact on portability.

Ok. I got that point the first time you made it.
I don't disagree with that. Had your post not at least implied that 0
was non-portable I probably would not have replied to you at all.

And thank you for setting me right.
 
F

Flash Gordon


Ah.... I misunderstood. Apologies. Btw.

No problem. Usenet would be more boring without the misunderstandings
:)
This is the second time you
spell'broken' as 'brocken'. I'm not nagging you about typo's (I hate
that myself), but in this case i'm wondering wether there is any
special intention to it (since you seem to spell it that way
consistently).

It's just bad spilling. I've managed to brake the spooling chucker on my
email client and have not yet got around to repairing it.

I tend to spill a lot of words by knowing patterns, and it just happens
that broken fits in to my pattern for using "ck", so it tends to get
spelt as "brocken" unless a split chicken corrects it.

BTW, my spelling is bad because I'm dyslexic. Part of my coping
mechanism is to always enable the automatic spelling checkers in every
application so normally people don't see much evidence of my dyslexia.
The non-zero null-pointer, not the zero 'success' value.

The non-zero null pointer is only a pain because you can't use calloc or
memset to blank a structure containing pointers, something which would
be useful to me. I can't see any other problem with it.

And thank you for setting me right.

I've posted enough howlers in my time. Admittedly I *try* to avoid them,
but...
 
D

dandelion

It's just bad spilling. I've managed to brake the spooling chucker on my
email client and have not yet got around to repairing it.

:) You remind me of a certain "french" cop...

Part of my coping
mechanism is to always enable the automatic spelling checkers in every
application so normally people don't see much evidence of my dyslexia.

I would not have noticed either. Only the "brocken" made me curious (it
means "chunk" or even "big chunk" in german and there's even a mountain
called "Der Brocken"). For the rest, your typo-frequency did not strike me
as being extra-ordinary.

My (occasional) bad spelling is just due to rampant sloppyness.
The non-zero null pointer is only a pain because you can't use calloc or
memset to blank a structure containing pointers, something which would
be useful to me. I can't see any other problem with it.

:) Try adressing a structure at *physical* address 0x0000 as I had to do
recently when adjusting the entries in an Interrupt Vector Table. Chris
Torek wrote a good pot on that (See "IVT at address 0").

I've posted enough howlers in my time. Admittedly I *try* to avoid them,
but...

Errare humanum est.
 
F

Flash Gordon

:) Try adressing a structure at *physical* address 0x0000 as I had to
:do
recently when adjusting the entries in an Interrupt Vector Table.
Chris Torek wrote a good pot on that (See "IVT at address 0").

Personally I would expect the implementation to actually document a way
to achieve the required result. It would not be portable, but an IVT is
inherently non-portable anyway.
Errare humanum est.

I only know what that says because I know it in English.

To err is human, to derefference null is undeffined.
 

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
474,156
Messages
2,570,878
Members
47,404
Latest member
PerryRutt

Latest Threads

Top