Segfault City

S

Skarmander

The problem is that the use of a nonstandardizable and aliasing
language causes the confusion.

No generalization can be made world wide concerning the universality of
argc and argv. I've maintained code in Red China, and I am only amused
by these people in the USA who make unsupported generalizations about
what is "meaningful".
Do the people in Red China use compilers where 'main' isn't named 'main' [*]?

To C programmers around the world, "int main(int argc, char *argv[])" (with
some minor variations) is an idiom, regardless of their native language.

I could see how a Chinese programmer might choose to forego the idiom and
name the arguments something else, but even that Chinese programmer would be
acting foolishly. 'argc' would be a better choice than any name in your
native language that means "integer representing the number of program
arguments", just as "#define AND &&" isn't better than just remembering what
logical conjunction is in C.

[*] They probably do have compilers that allow you to set the program entry
point yourself for circumstances where a traditional 'main' doesn't make
sense (freestanding environments, mostly), but this is orthogonal to my point.

S.
 
M

Michael Mair

Because you're engaged in a campaign of personal destruction as you
were with Schildt.

IMO, it was not wise of Richard to post here before discussing
the matter with you via e-mail -- but I think so only for the
reason that you mentioned his name on the webpage under discussion.

It is certainly not wrong to highlight examples of particularly
wrong statements and low quality code.

I do not know about any special relationship between Richard
Heathfield and Herbert Schildt but after having read a fairly
recent book of his a couple of years ago, I developed the
opinion that his books are dangerously off the mark -- without
"help" by the community let alone Richard Heathfield.

If I were you, I'd do the smart thing and ask for a code review
around here. Put a corrected version up on your page -- it will
still illustrate part of your point but not leave you open to
the justified criticism that you provided a particularly bad
piece of code to illustrate it.

No, the mark of a bad programmer is inability to think outside the
particular set of chosen inputs and your insistence that C is still
usable for new development.

Well, your code would not pass code review in any company I ever
worked for -- and not because of "small stuff".
This reflects bad on your qualification to harp on about C being
best dead and gone "as a professional".
I think that C is not the first choice for many tasks but will
continue to be used for new development in certain areas for a
long time. If you happen to work in another area, then you can
consider C as not being your first, second, third, or even tenth
choice.

Do respond. I need a laugh and it seems you are ... well, not awake,
but posting. Are you drunk? Are you stoned?

Considering the quality of your comments, I can understand why
Richard did not bother to contact you via e-mail first.
<snip>
Could you please stop quoting signatures?


Cheers
Michael
 
C

CBFalconer

Andrew said:
.... snip ...

What, if anything, can it be guaranteed will be > '9' in standard C?

I don't know, but:

unsigned int ch;

if (((ch = getchar()) - '0') > 9) {
/* ch is not a digit */;
}
else {
/* ch is a digit */;
}
 
C

CBFalconer

Eric said:
Andrew Poelstra wrote:
.... snip ...

Oooh, what fun! Richard is the target of a vendetta!
He'd better check his bed for horses' heads -- or perhaps
he needn't bother; the vendettor seems like someone who's
better acquainted with the opposite end of the animal.

Doesn't take long to evaluate, does it? The end product is better
known as Nilgewater in other circles. In comp.programming there is
a sport known as Nilges-baiting. Not really suited for here,
because he is consistenly atopical.
 
F

Friedrich Dominicus

CC: (e-mail address removed), which I'm assuming is Edward G. Nilges.

This is spinoza1111 who is Edward G. Nilges, author of Build Your Own
.Net Language and Compiler [and please, don't use C, thank you very
much.]
yes indeed and you write the same bloody wrong code as you always did
and your arguments havn't got better voer time.
I abandoned C shortly thereafter because each time I realized a new
deficiency, a new source of undefined behavior, I would write a
preprocessor macro or similar tool to encapsulate the cure.
Yeah you solution is hiding bade coding behind Macros, that's nothing
new to the regulars.

I bet this threads will not end before 500 posts, you blaming C for
every fault it allows you, other in pointing out that you have no clue
about C programming.

Friedrich
 
R

Roberto Waltman

..... What puzzles me is the implication elsewhere
that if two strings appear, either adjacently or on separate lines,
they will be magically concatenated as in rexx. You may be right.

Actually, they are magically concatenated as in C. ;)
(Thanks for the rexx info anyhow)

From ISO/IEC 9899:1999

5.1.1.2 Translation Phases
....
6. Adjacent string literal tokens are concatenated.

7. White-space character separating tokens are
not longer significant. ...
 
B

blmblm

[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

I somehow missed the author's name at the top of the -- entry?
article? post? -- but well before I got to the actual code
I had made a guess that proved to be correct. The man does have a
distinctive style (though probably it was a major clue that it's
you drawing people's attention to the entry).

The use of macros seems somewhat C-idiomatic, but not the names
chosen for the arguments to main. (Who else .... ) 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.
 
J

John Smith

Richard 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.

It compiled cleanly with Digital Mars, Pelles C and lcc-win32.
Errors for missing or misplaced braces just after the first "if"
block in main()with Open Watcom. In the cases where it compiled,
it ran without a segfault.

In any event, the output is ponderous and confusing and there is
far too much superfluous code: the core code for the Sieve of
Eratothenes can be written in about a half dozen lines of C.

JS
 
B

blmblm

(e-mail address removed) said:

[ snip ]
C offers no guarantee that there is any character with a code point higher
than '9'. In EBCDIC, the code point of '9' is 249, so there are just six
characters (none with well-defined interpretations) with higher code
points. So Andrew's point is perfectly valid. It was also sufficiently
grammatical than I could understand it.

I think if you parse the "What, if anything" sentence just so, it's
perfectly grammatical, though it does read a bit strangely.
 
B

blmblm

[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

Something I wondered about was why the code tests numbers up through
half the highest value (call it N), rather than up through sqrt(N),
which is clearly (?) sufficient. Most discussions I've read of this
algorithm stop at sqrt(N), though perhaps the original algorithm
didn't?
 
R

Richard Heathfield

(e-mail address removed) said:
Because you're engaged in a campaign of personal destruction as you
were with Schildt.

The important thing is that C students learn how to write C properly. The
characteristic you share with Schildt is that you are endeavouring to teach
C without actually knowing it, and /that/ is what is destructive.

No, the mark of a bad programmer is inability to think outside the
particular set of chosen inputs

That's another mark, it's true, but my point is still perfectly valid.
and your insistence that C is still usable for new development.

Well, that's certainly an opinion, although I doubt whether it will be
shared by many here in comp.lang.c.
OK, this is complete nonsense. Are you pulling my leg?

No, I'm perfectly serious, and no, it's not even incomplete nonsense, let
alone complete nonsense. What I have said is accurate.
You read in the standard that "C offers no guarantee with a code
point..."

Not those exact words, but yes, it's true that the Standard offers no such
guarantee.
But it MEANS that there CAN be. Can you read?

Yes, I can read, and yes, there can be characters with a higher code point.
And to use EBCDIC, a completely obsolete encoding, obsoleted by ASCII
and then international 16 bit encoding...the mind boggles!

Some programmers don't get to choose their character set.
In ASCII, for which nearly all C code is written, the letters follow
the numbers! If the user enters A your "correct code" breaks?

Not at all. But to rely on the letters following the numbers (which, I
hasten to add, your code does not) would be silly.
[The "standard" may require the C runtime to treat the digits as
following the characters.

It doesn't. The guarantees given by the Standard w.r.t. code points are as
follows:

1) all characters in the basic source and execution character sets have
positive values;
2) '0' to '9' are in numerical order and contiguous.
The fact is that real compilers don't, and
use the encoded value. What this illustrates is the UNUSABILITY of the
standard, and consequently that it is extremely unwise, to the level of
professional malpractice, to recommend C for new development, as you
appear to.]

No, it illustrates that you don't understand the Standard's guarantees about
code points (see above).
Are you for real? And you are sitting on your fat ass telling me I
don't know how to program?

Well, I don't own a donkey, fat or otherwise, but apart from that you're
broadly correct, yes.
But then you say that there are "just 6 characters" as if the small
number of characters makes it probable that your code won't break!

No, I'm saying that to rely on character ordering that is not guaranteed by
the Standard renders code non-portable to systems where that reliance is
misplaced. I will again say, however, that your code does *not* fall foul
of this particular issue. We are discussing a minor point raised by Andrew
about a curious way of phrasing a character test, not an error in your
code.
"My program is standard C, therefore the user has no right to send
characters with t a value higher than 9" is the zenith of arrogance.

But nobody is saying that.
And you use this as a reason for presenting code which BREAKS if there
IS a code point after all (c - 0 with no test for greater than 9)????

Not at all.
This is worse than I thought.

You seem to be using C on an IBM mainframe with the SAS compiler, and
pompously talking about C based on a misreading of the standard!

Please cite and explain the relevant section of the Standard that you think
I am misreading.
And if your compiler runs on an ASCII system, it has to jiggle
characters at runtime to make sure 9 is the "last" character.

No, not at all. You seem to have misunderstood my point completely.
And C is an "efficient" language?

No, C is a programming language. Whether C programs are efficient depends on
how they are written. It is easily possible to write inefficient programs
in C, just as it is easily possible to write inefficient programs in any
sufficiently powerful programming language. (The caveat is only there
because I suppose it is possible to conceive of a programming language so
limited that all its expressible programs are efficient, but that would
almost certainly be a very limited language indeed.)
Without being even aware that given aliasing, C can't be standardized
in a modern sense?

Well, I'll let you take that up with ISO.
And icing on the cake..."it was also sufficiently grammatical THAN I
could understand it".

Do respond. I need a laugh and it seems you are ... well, not awake,
but posting. Are you drunk? Are you stoned?

No, but I am in the mood to write a Sieve. See below.


First, though, I'll recompile your program to allow writeable strings, and
see what it tells me:

me@here:~/scratch> ./foo 1 10 10
Sieve of Eratosthenes primes from least prime >= 3 to greatest prime <= 10
Sieve contains 10 entries
3
Sieve contains 134520391 entries
5
Sieve contains 134520391 entries
7
Sieve contains 134520391 entries
Number of primes found: 3
Number of nonprimes found using the sieve: 1
Number of nonprimes found using brute force: 0
Number of primes in the sieve: 3
Number of primes displayed: 3
Time in approximate seconds: 0

Curious how the sieve expands suddenly, isn't it?

Incidentally, changing the sieve size to 100000, I get a runtime (as
measured by time(1)) of 5.8 seconds with output redirected to /dev/null (to
eliminate console updating, which is slow). With a sieve size of 1000000,
the runtime is positively chelonian, and I canned it after about 7 minutes.

Here are some comparative performance statistics:

Max Execution time (seconds, excluding display)
prime
value My program Your program
10 0.003 0.002
100 0.003 0.002
1000 0.003 0.003
10000 0.004 0.081
100000 0.014 5.808
200000 0.017 20.102
300000 0.024 46.097
400000 0.060 too long

And here's my program, which, in the interests of fairness, I have made 200
lines long:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <time.h>
#include <math.h>

#define DEFAULT_SIEVE_BYTES 1024UL
#define DEFAULT_SIEVE_SIZE (DEFAULT_SIEVE_BYTES * CHAR_BIT)

/* Bitmapping macros */

#define BYTE(array, bit) ((array)[(bit) / CHAR_BIT])
#define MASK(bit) (1 << ((bit) % CHAR_BIT))
#define SET_BIT(array, bit) \
BYTE(array, bit) |= MASK(bit)
#define CLEAR_BIT(array, bit) \
BYTE(array, bit) &= ~MASK(bit)
#define TEST_BIT(array, bit) \
(!!(BYTE(array, bit) & MASK(bit)))

/* Helper function prototypes */
void show_help(void);
void do_sieve(unsigned long first, unsigned long last);
void sort_two_uls(unsigned long *a, unsigned long *b);

/* program entry point */
int main(int argc, char **argv)
{
int rc = EXIT_SUCCESS;

/* start the clock */
time_t start = time(NULL);

/* capture and crop limits */
if(argc > 2)
{
char *end1 = NULL;
char *end2 = NULL;
unsigned long first = strtoul(argv[1], &end1, 10);
unsigned long last = strtoul(argv[2], &end2, 10);
sort_two_uls(&first, &last);
if(end1 == argv[1] || end2 == argv[2])
{
show_help();
fprintf(stderr,
"Invalid argument %s\n",
end1 == argv[1] ? end1 : end2);
rc = EXIT_FAILURE;
}
else if(last < 2)
{
printf("Trivial case - no primes in list.\n");
rc = EXIT_FAILURE;
}
else
{
/********************
* All is well. *
* Go do the sieve! *
********************/

do_sieve(first, last);
}
}
else
{
show_help();
rc = EXIT_FAILURE;
}
if(rc == EXIT_SUCCESS)
{
/* Stop the clock and display the runtime */
time_t end = time(NULL);
fprintf(stderr,
"Approximate execution time (seconds): %.0f\n",
difftime(end,
start));
}
return 0;
}

void do_sieve(unsigned long first, unsigned long last)
{
unsigned long candidate = 0;
unsigned long root = 0;
unsigned long scratch = 0;
unsigned long primes = 0;

unsigned char default_sieve[DEFAULT_SIEVE_BYTES] = {0};
unsigned char *sieve = default_sieve;
if(last > DEFAULT_SIEVE_SIZE)
{
size_t bytes = last / CHAR_BIT + 1;
sieve = calloc(bytes, sizeof *sieve);
if(sieve == NULL)
{
fprintf(stderr,
"I can't build a sieve that big.\n"
"I'm using the default sieve size\n"
"(which is %lu) instead. Sorry.\n",
DEFAULT_SIEVE_SIZE);
sieve = default_sieve;
last = DEFAULT_SIEVE_SIZE;
if(first > last)
{
first = last / 2;
fprintf(stderr,
"That means I have to adjust\n"
"the range as well. I am now\n"
"using the range %lu - %lu\n",
first, last);
}
}
}

/* OKAY! We can now use our sieve. At present, it
* is populated entirely with zero-bits. We will
* take 0 to mean "might be prime", and 1 to mean
* "is definitely not prime". At the end of the
* process, of course, 0 will mean "IS prime".
*/

/* find the root of the upper limit */
root = sqrt(last) + 1;

/* Mark 0 and 1 as being non-prime */
SET_BIT(sieve, 0);
SET_BIT(sieve, 1);

/* Mark 4 as non-prime */
SET_BIT(sieve, 4);

/* Mark all numbers of the form 6n, 6n + 2, 6n + 3
* and 6n + 4 as being non-prime.
*/
for(candidate = 6; candidate <= last; candidate += 6)
{
SET_BIT(sieve, candidate);
SET_BIT(sieve, candidate + 2);
SET_BIT(sieve, candidate + 3);
SET_BIT(sieve, candidate + 4);
}

for(candidate = 5; candidate <= root; candidate += 2)
{
for(scratch = candidate * 2;
scratch <= last;
scratch += candidate)
{
SET_BIT(sieve, scratch);
}
}

for(candidate = first; candidate <= last; candidate++)
{
if(!TEST_BIT(sieve, candidate))
{
printf("Prime found: %lu\n", candidate);
++primes;
}
}

fprintf(stderr, "Total primes found: %lu\n", primes);

if(sieve != default_sieve)
{
free(sieve);
/* help to protect against maintenance errors */
sieve = NULL;
}
return;
}

void show_help(void)
{
const char *help[] =
{
"\n This program uses Eratosthenes' Sieve to work\n",
" out all the primes between two limits. Please\n",
" run the program again, specifying both limits.\n\n",
NULL
};
int i = 0;
do
{
fputs(help[i++], stderr);
} while(help != NULL);
return;
}

void sort_two_uls(unsigned long *a, unsigned long *b)
{
if(*a > *b)
{
unsigned long t = *a;
*a = *b;
*b = t;
}
}
 
B

Ben Pfaff

Richard Heathfield said:
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.

Someone lets *Nilges* teach C? Where? Has his supervisor been
notified?
 
R

Richard Heathfield

(e-mail address removed) said:
And I should worry about EBCDIC?

If you want your program to work on EBCDIC systems, yes. But EBCDIC is
beside the point, which is that when portability is a highly desirable
objective, it's a bad idea to introduce unnecessary dependencies into your
code. (And I will say again that you did not in fact do this.)
It is true, based on my experience in
teaching SAS C in 1989 that there are "C" compilers where you MIGHT get
away with your nonsense. The code for these compilers is NONPORTABLE to
ASCII machines as-is.

There's no nonsense here to get away with, so what you claim is false, and
your "experience" is irrelevant to what the Standard says about character
sets.
Which shows that in terms of modern languages there is literally no
such thing as the C programming language. It is an illusion.

It's a fabulous illusion, then, given that so many of us earn our bread and
butter from writing programs in it.
Oh, ok, it MIGHT be the highest character therefore your wonderful code
can ignore the possibility (which the "might be" implies) that it is
not?

It's trivial to make it a non-issue. I have already shown how to do this.
 
B

Bill Pursell

Richard said:
void show_help(void)
{
const char *help[] =
{
"\n This program uses Eratosthenes' Sieve to work\n",
" out all the primes between two limits. Please\n",
" run the program again, specifying both limits.\n\n",
NULL
};
int i = 0;
do
{
fputs(help[i++], stderr);
} while(help != NULL);
return;
}



I'm curious to know the motivation for making help
an array. Why not just:

const char *help = "\n This program...";

I presume it's simply a method to protect future
expansion from breaking the 509 character
minimum length guarantee, but I'm curious to
know if there is anything else.
 
W

Walter Roberson

And to use EBCDIC, a completely obsolete encoding, obsoleted by ASCII
and then international 16 bit encoding...the mind boggles!

ASCII: 1963
EBCDIC: 1964


I'm not sure how an older encoding manages to "obsolete" a newer encoding?
 
R

Richard Heathfield

Bill Pursell said:
I'm curious to know the motivation for making help
an array. Why not just:

const char *help = "\n This program...";

I presume it's simply a method to protect future
expansion from breaking the 509 character
minimum length guarantee, but I'm curious to
know if there is anything else.

No, that's just how it flowed out of my fingers. I didn't anticipate
exceeding the output limit for fprintf with this particular program; it's
just that my fingers wanted an array, so that's what I got. My fingers
write a small but significant fraction of my C code without needing a huge
amount of external input.
 
A

Andrew Poelstra

Andrew said:
[X-posted, and followups set]

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

Just out of curiousity, did you stumble upon that while Googling your own
name? I'm not accusing you of arrogance, but it's interesting that he
mentions and insults you specifically in his preamble.
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.

Ooh. Segfault City. Where all bad programs go to die. :)
(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.

I stopped reading after the first function. I wasn't sure why he kept

Which disqualifies you from a technical discussion. Why are you
posting?

How does that disqualify me? I read through an entire function that could be
replaced with... let's see... 4 characters: -'0'. That's a lot more tolerance
than a lesser programmer might have. Why on earth would you use a function at
all?

What is simpler?

n = c - '0';

or

n = char2digit (c);

The former is a well-known construct. The latter is a function call that looks
exactly like any other function. One of them I can glance over and see what it
does, while the other requires me to stop and look.

They both require checks if you want to ensure that c is a digit. It's just
that's one's shorter, simpler and more efficient.

So, the question now seems, why are /you/ posting?
It was a straightforward test for numerics. Again, are you qualified to
be in this discussion?

You stopped trying to understand things twice, so your opinion is
worth...what?

See above. I eventually realized that I would have to just rewrite the code to
have any hope of reading it. Your overly-long variable names, unnecessary casts,
useless functions, Hungarian notation, overly-spaced parentheses, and use of //
comments just didn't seem worth trying to understand.
This isn't grammatical therefore I do not fully understand it. If you
are saying there is no character greater than 9, well I wish you all
the best in your future career. You'll need it.

Don't quote signatures. You've been doing that all thread, and it's getting
annoying. My question was perfectly grammatical. Perhaps you should have
studied English more in high school.

In fact, there /isn't/ any guarantee of a character greater than '9' in C.
I would think that since I understand the C standard far better than you,
perhaps /I/ should be wishing /you/ the best on your future career.
 
R

Richard Heathfield

Andrew Poelstra said:

I read through an entire function that could
be replaced with... let's see... 4 characters: -'0'.

Or removed completely, since all he's doing is avoiding a strtoul call, and
it actually takes him *two* functions to do it. The proper solution is to
call strtoul in the first place!

<snip>
 
M

Malcolm

Andrew Poelstra said:
How does that disqualify me? I read through an entire function that could
be
replaced with... let's see... 4 characters: -'0'. That's a lot more
tolerance
than a lesser programmer might have. Why on earth would you use a function
at
all?

What is simpler?

n = c - '0';

or

n = char2digit (c);

The former is a well-known construct. The latter is a function call that
looks
exactly like any other function. One of them I can glance over and see
what it
does, while the other requires me to stop and look.
Personally I'd use char2digit(), or, better, chartodigit().
There is a real issue with trivial functions. Runtime overhead is sometimes
a problem, but usually doesn't matter. The question is whether it is easier
to read a mnemonic or an actual line of code. Also, in functions which would
otherwise be leaf, you don't necessarily want to create a dependency just
for the sake of it.

However I usually go the function route. My code is littered with clamp(),
lerp(), max(), min(), uniform() and so on.
 
P

pete

Andrew Poelstra wrote:
I stopped reading after the first function. I wasn't sure why he kept
casting chars to ints,
as though there wasn't implicit casting going on by default.

The first function at
http://www.developerdotstar.com/community/node/291
only casts char to int, once.

The other two casts, cast int to int.

int char2Number( char chrInChar )
{
int intInCharValue = ( int )chrInChar;
int intZeroValue = ( int )'0';
if ( intInCharValue < intZeroValue
||
intInCharValue > ( int )'9' ) return -1;
return intInCharValue - intZeroValue;
}
 

Members online

Forum statistics

Threads
473,777
Messages
2,569,604
Members
45,218
Latest member
JolieDenha

Latest Threads

Top