Segfault City

M

Malcolm

[X-posted, and followups set]

I found something interesting on the Web today, purely by chance.

It would be funny if it weren't so sad. Or sad if it weren't so funny.
I'm
not sure which.

http://www.developerdotstar.com/community/node/291

[ snip ]
[ .... ] I'm not sure
what to make of string2number, but perhaps there's a good reason
I'm not thinking of to not use one of the library functions (e.g.,
atoi or strtol) that would seem to accomplish the same thing.

Because in fact few actually existing C environments conform to the
most current Standard I decided to roll my own. I was at the time
engaged in a global computing project for people who can't afford clean
water, let alone rush out and buy a conforming implementation.

There may be no point in following up here, since Mr. Nilges says
he's left the building. In case he changes his mind, though:

And yet you have no qualms about using other library functions --
strlen, strcmp, strcat, and printf being the ones I noticed in a
quick (re)scan through the code.

Seems inconsistent, but perhaps you aren't bothered by that.
To be fair it is meant to be teaching code.
In real code one would of course use strtol() to obtain a safe conversion of
an integer. It is such a common operation that a function has been provided.

However the function isn't difficult to write, so I can see that students
might want their own version of it. printf() has to be provided as a "magic
function". beginners probably only have a very hazy idea of how it works,
but they need it to see some output.

That's not the justification Nilges gives.
 
H

Herbert Rosenau

int ctoi(char c)

int ctoi(int c)
{
int i = -1;
if (c >= '0' && c <= '9')
{
i = c - '0';
}
return i;
}

lovecreatesbeauty

a bit shorter

inline int ctoi(int c) {
return isdigit(c) ? c - '0' : -1;
}

Or if I have to be sure that it will compile on pre ANSI compilers I
would just
#define CTOI(c) isdigit(c) ? (c) - '0' : -1

In contrast to a dumbass who means he were a C teacher (but knows not
even a bit about the standard) I would never use strcat() to
concentate a to a string constant. Anybody who knows a little bit
about C knows that that will end in the lands of undefined behavior.

Yeah, it is fine to use selfdocumenting names but UPN names are out of
order since mor than 20 years now. Inventing own names for argc and
argv is really lame and does not speak for a person who names himself
a teacher.


--
Tschau/Bye
Herbert

Visit http://www.ecomstation.de the home of german eComStation
eComStation 1.2 Deutsch ist da!
 
H

Herbert Rosenau

Richard, I will ask for your help on following my code snippet. It will
be my pleasure again to read anyone's comments on it.

int ctoi(char c)
{
int i = -1;
if (c >= '0' && c <= '9')
{
i = c - '0';
}
return i;
}


I remember someone ever said that there is not release or debug version
in C language. The C language (preprocessor) has Macros, functions. A
particular user (library) function is not a part of the features the C
language. I do not think there is differences between the assert() and
a simple if statement.


There are differences between debug and nodebug versions. For that
each compiler has a switch to translate one of both.

Differences:
- in nodebug versions (NDEBUG gets defined by the compiler)
- assert() gets translated to nothing
so assert helps only during debug but not in productive code
- even when assert() were in productive code a sigsev or
crash with/without memory dumb is ok during debug but
not when a program is in productive mode. Data loss is
the result on that.

- in debug vversion (NDEBUG isd NOT defined)
- assert() can help in finding programmer errors quickly
but is no choice to catch user errors.

Use assert() to catch errors in programmers logic (unwanted data
types, unwanted parameters and so on.
Don't use assert() to catch errors a user can correct - like mistyping
a letter instead of a digit. A failsave program will give the user a
chance to correct his error and does not simple result in a dump.



--
Tschau/Bye
Herbert

Visit http://www.ecomstation.de the home of german eComStation
eComStation 1.2 Deutsch ist da!
 
H

Herbert Rosenau

convert character to numerical value
Params: ch - digit in character encoding
Returns: numerical value of the digit. behaviour if passed non-digit is
undefined
*/
int chartonumber( char ch)
{
assert( isdigit(ch) );

Programmers error. assert will end the program instead to give the
user a chance to correct his error. Never use assert for an error the
user may correct without restart the program and retype all the data
he has already typed in, restore a database that gets corrupted
through the sigsev, restore lots of data files corrupted through the
unwanted assert()......
return ch - '0';
}

Nice, easy to see. And if someone passes a non-digit to such a function, it
deserves to kick.
And no, it isn't qute conforming but it's conforming enough. Anyone care to
point out the technical difficulty?


Yes. assert is a debug function only. In well optimised productive
code it will resolv in nothing, so here converting something not a
digit to some integer value will occure.

Never use assert() for anything else as to check for programmers
errors. If you can't distinguish between user and programmer error
don't use assert. In debug it will you help nothing, in productive
environment it is at best harmful when you use the debug version there
or when you use the productive executeable it will give you unwanted
results because assert() is removed.

Write real if() and print out error messages but let not crash the
program only because user made a type, a file is unread/writeable.....

--
Tschau/Bye
Herbert

Visit http://www.ecomstation.de the home of german eComStation
eComStation 1.2 Deutsch ist da!
 
B

Barry

Richard Heathfield said:
[X-posted, and followups set]

I found something interesting on the Web today, purely by chance.

It would be funny if it weren't so sad. Or sad if it weren't so funny. I'm
not sure which.

http://www.developerdotstar.com/community/node/291

This "teacher of C" demonstrates his prowess with a masterful display of
incompetence in a 200-line program that travels as swiftly as possible to
Segfault City.

(Actually, using my normal gcc switches, it doesn't even get past TP3, but
it will at least compile if you just use gcc -o foo foo.c, after hacking it
around a bit to do things like mending the line-spanning single-line
comments and string literals, which - in fairness to the author - are
probably an artifact of the Webification of the code.)

I wonder how long I'll take to stop laughing.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)

After reading most of the posts on the thread it's quite obvious the
coder is clueless. Any programming language would be beyond his
grasp.

And then I looked at some of the links.
It is truly sad to think this person is teaching anyone anything.
 
P

pete

Use assert() to catch errors in programmers logic (unwanted data
types, unwanted parameters and so on.
Don't use assert() to catch errors a user can correct - like mistyping
a letter instead of a digit. A failsave program will give the user a
chance to correct his error and does not simple result in a dump.

To me, the presence of "assert" in code
indicates that the code is still a work in progress.
 
F

Frederick Gotham

pete posted:
To me, the presence of "assert" in code
indicates that the code is still a work in progress.


To me, it indicates that the programmer is fully aware of her "human-
ness", and makes intelligent decisions based on their acceptance of their
human-ness.

We make mistakes. Plain and simple. If I had a $1 for every time I made a
silly coding mistake, I'd be a rich man. But that doesn't mean I don't or
can't write quality code.

"assert" is a wonderful thing... it's our own little private
investigator. Instead of having to look through our code to spot a
stupid, silly mistake, it's throws a stone at our window at tells us
exactly where things are going wrong.

To remove an "assert" statement simply because you think you're
omnipotent, is, in my own opinion, pretentious.

I believe the following function to be high-quality, and that it should
be unchanged when brought into the Release version:

unsigned CharDigitToInt( int const c )
{
assert( c >= '0' && c <= '9' );

return c - '0';
}


(Of course we could debate the usage of "isdigit", but you get the idea
nonetheless)
 
P

pete

Frederick said:
pete posted:


To me, it indicates that the programmer is fully
aware of her "human- ness",
and makes intelligent decisions
based on their acceptance of their human-ness.

Abnormal program termination,
as a means of handling invalid argument values,
isn't intelligence, it's just lack of imagination.
 
B

Bill Pursell

pete said:
Abnormal program termination,
as a means of handling invalid argument values,
isn't intelligence, it's just lack of imagination.

Assert also tells the maintenance programmer what
the original coder expected. Consider the following
2 cases:

1)
/* foo requires a in the range 5 to 10, inclusive */
int foo(int a) { /* do something */ }

2)
/* foo requires a in the range 5 to 10, inclusive */
int foo (int a) { assert ( a >=5 && a < 10); /*...*/}

I much prefer the second case for 2 reasons:
first, it reveals that the comment wasn't quite accurate,
or at least it disambiguates the English text, and
second, the program bombs when I use foo
incorrectly instead of simply failing because of
some subtle bug that is introduced due to my
failure to notice the comment and subsequent
misuse of foo.

Assert is not being used to terminate the program
in the presence of invalid data, it is being used
to terminate the program due to programmer error.
This is not a lack of imagination,
rather it is a method of communicating the design
in a precise manner which is impossible to
ignore. (except by defining NDEBUG, of course.)

Any assumption you make about the data that
is substantiated by your design should be explicitly
asserted.
 
P

pete

pete said:
Abnormal program termination,
as a means of handling invalid argument values,
isn't intelligence, it's just lack of imagination.

Actually, in practice there are plenty of times
when I can't think of anything better
than abnormal program termination.
But I usually handle those with an if statement
and some message output and a call to exit.
As much as I can, I try to use a return value
from a function to indicate an error
so that I can do all of my program termination from main.
 
R

Richard Heathfield

pete said:

To me, the presence of "assert" in code
indicates that the code is still a work in progress.

You mean you take them out? Why? The whole point of them is that you can
strip them out with NDEBUG.
 
F

Frederick Gotham

pete posted:
Actually, in practice there are plenty of times
when I can't think of anything better
than abnormal program termination.
But I usually handle those with an if statement
and some message output and a call to exit.
As much as I can, I try to use a return value
from a function to indicate an error
so that I can do all of my program termination from main.


Yes, but we're talking about debug mode.

If it were the Release version, I'd want it to be as efficient as
possible; "assert" is great for this as it evaporates when you leave
debug mode. And when you ARE in debug mode, it tells you exactly where an
error has occurred.


I see "assert" as being a win-win situation. It costs nothing, as it
evaporates in Release mode, and it also helps out in Debug mode.
 
P

pete

Richard said:
pete said:



You mean you take them out?

No. I don't recall ever seeing assert,
in code started by somebody else, that I was working on.
The only time I write assertions,
is to check the values of changable macros.
 
K

Keith Thompson

Richard Heathfield said:
Malcolm said:
[...] if you provide a library you also have to
build a linker which only links in functions actually called. It is a lot
easier to tell the programmer to write his own strlen() and isdigit().

Even in /that/ eventuality, it still makes much more sense to write your own
character classification functions, and then *use* them, than it does to
sprinkle character classification code all over your program.

If isdigit() didn't exist, it wouldn't be *entirely* necessary to
invent it. Given the standard's guarantees about the digits being
contiguous, I might just write
c >= '0' && c <= '9'
rather than writing and calling a function that does the same thing
(if I weren't doing the test more than once or twice, and I wasn't
also writing a number of other character classification functions).

But of course isdigit() does exist, and in the real world there's no
point in avoiding it or reinventing it in any code that depends on the
existence of the standard library anyway (say, by using printf() and
strlen()).

In my opinion, given the existence of isdigit(), calling it is better
than doing the explicit test above, but not that much better. I'm not
sure that I'd bother to change it if I saw it in code that I was
working on. (There's always the risk that I'd break something by
forgetting to cast the argument to unsigned char.)
 
K

Keith Thompson

Herbert Rosenau said:
int ctoi(int c)


a bit shorter

inline int ctoi(int c) {
return isdigit(c) ? c - '0' : -1;
}

Or if I have to be sure that it will compile on pre ANSI compilers I
would just
#define CTOI(c) isdigit(c) ? (c) - '0' : -1
[...]

I *hope* you meant

#define CTOI(c) (isdigit(c) ? (c) - '0' : -1)

And of course this evaluates its argument twice, so the caller has to
be careful about that.

I'd probably just drop the "inline" (and add "static" if it's only
used in one file) and count on the compiler to inline it for me if it
chooses. If it turned out to be a performance bottleneck, *then* I
might think about making it a macro.
 
M

Malcolm

pete said:
No. I don't recall ever seeing assert,
in code started by somebody else, that I was working on.
The only time I write assertions,
is to check the values of changable macros.
assert() is only useful in debug mode.
In a real run with a non-programmer in charge of the computer, really you
might as well just segfault or crash as trigger an assertion failure.
However funtions spend a lot of time being debugged, my functions also get
copied a lot from one program to another, because of the type of programming
I so. So if you pass a non-digit to a digittonumber() function, for example,
you want it to trigger an assertion fail early on in testing. You don't
really want a -1 returned, because that might mean that your input is
slightly off, which would be a difficult problem to track down.

Sony only allow two error messages, "Drive door open" and "Disk dirty". So
if you are writing a video game for the, assert() and be redefined to print
a "Disk dirty" message to the screen. The user stops the program, cleans the
disk, and the error is overcome.
 
M

Malcolm

Richard Heathfield said:
Malcolm said:



No, there isn't. If you are writing a video game, there is no excuse
whatsoever for a non-digit character ever reaching such a function,
because
the game-supplied data is tightly controlled and should have been
validated
before shipping, and user-supplied data can be restricted at the input
stage so that only appropriate data can be entered. Video games have
considerable freedom in that regard, since they have access to more
sophisticated data capture techniques than are available in standard C.
Should, yes, but that's the incompetent colleague who called your function
with a non-digit at fault. The question is, once the disaster has happened,
what is the least damaging thing to do. Shut down the game, or display the
wrong score?
There isn't necessarily an easy answer to that one, but normally it is
better to keep things moving.
You'd be amazed at what players notice - especially since many modern
video
games are so fast-paced that players /have/ to be able to notice tiny
things very quickly if they are to do well at the game. For example, in a
driving game my son plays, he can spot instantly whether a car in the
distance is a police car, without the benefit of sirens and lights!, by
the
presence or absence of a *single pixel* representing the (unlit) roof
lamp.
He would be very likely to spot an anomaly caused by a bug in the program
(and often does).
I don't actually like that. If players are looking for pixels the they are
looking for the limitations in your graphics, which isn't very desirable.
But of course players find strategies for beating the game, and the fact
that they bother is testimony to the play value of the game. Do you remember
the BBC game Elite? That suffered from the problem that you could shoot an
enemy ship when it was a little pixel, slightly fatter than a star. So the
game became line up the pixels and shoot, and good players never got to see
the nice graphics of ships shooting missiles at you.

There will be bugs in the program he doesn't spot, almost certainly. A
modern game consists of several extremely complicated components put
together with many interconnections, and then hacked to make things run
faster. It is very hard to get them out on schedule, even harder to make
sure that they are bug free. However they are normally playable, that's
easier to achieve and test.
 
M

Malcolm

Richard Heathfield said:
Malcolm said:



Teaching what, precisely? Teaching how to do JTL overflow detection?
Praxis, and the hermeneutical deficiencies of an alienated producer paradigm
in which brevity is an attempt to conceal.
Actually I think someone taught by Nilges would go far. I'm just reading a
book "Plundering the Public Sector" about the NHS system. [National Health
Service, to non-Brits]. I'll post a review on my website.
 

Members online

Forum statistics

Threads
473,777
Messages
2,569,604
Members
45,216
Latest member
topweb3twitterchannels

Latest Threads

Top