Efficency and the standard library

N

Nick

Seebs said:
This is then followed by the "corresponding" example:

ch = getc(fp); /* read one character */
while (ch!=EOF) {
putchar(ch); /* print on screen */
ch = getc(fp);
}

This is actually probably correct, though horribly unidiomatic. Oh, wait,
found the bug; it's worse. "ch" is declared as a "char", meaning that on
many systems, it will spew an infinite stream of characters which have the
value you would get if you converted EOF to char. Since the entire POINT
of EOF is that it's a value which cannot be a character returned by getc,
and thus, is outside the range of unsigned char, that's sort of bad.

Putting the bug aside, I had experience of people writing C like that
around 1990. They'd been on some sort of course in some sort of
programming methodology (maybe SSADM, maybe not - it was a long time
ago). In this case, they ended up writing something like:

a = fgets(buff, SIZE, stdin)
while(a) {
do_things_with_a;
a = fgets(buff, SIZE, stdin);
}

All perfectly logical, but utterly un-idiomatic and (particularly when
things were a bit more complicated) it led you to looking at the two
identical lines wondering if they were in any way different.
 
N

Nick

Richard Heathfield said:
Nick said:
On Feb 22, 9:15 pm, Nick Keighley <[email protected]>
The beginning of wisdom for a [software engineer] is to recognize the
difference between getting a program to work, and getting it right.
-- M A Jackson, 1975
For which "software engineering" has had thirty years to give a
scientific procedure, and software engineering has failed.

only because Michael Jackson dropped out of programming to pursue a
popular music career.

When I heard that Michael Jackson had died, I was (a) somewhat
saddened, but not surprised (he's in his 70s, after all), and (b)
somewhat puzzled at all the public fuss. Thoroughly merited, but
rather unexpected nonetheless.

As it turns out, though, there are several Michael Jacksons, and it
was one of the others that had died.

Considering he was at school with Psmith I'd have thought he was even
older than that.

Nick, wondering if you were thinking of beer, the military, structured
programming or of yet another one.
 
R

Richard Bos

santosh said:
Even if I were a very good C programmer, I'd object to any publisher
who decided to describe me as "world famous programmer" on any C book
I were to write. Not everything is about marketing. I know evaluating
a book based on an emotional reaction to it's blurb is weak, but
still...

You seem to be mistaken about who the intended public for these books
are. They are in the "...in 24 hours" and "...for dummies" class, and
like those, are not marketed towards serious programmers.

Richard
 
C

Chris M. Thomasson

Chris M. Thomasson said:
Seebs said:
Anyone planning to invent this would be well-served by studying the
"mbufs"
in the BSD networking stack.

Indeed. I also enjoy the well known intrusive list technique:
_______________________________________________________
struct node
{
struct node* next;
};


struct foo
{
struct node node;
/* [whatever] */
};


#define foo_from_node(n) ((struct foo*)(n))
_______________________________________________________




The Linux User/Kernel and Windows User/Kernel-space code is quite fond of
intrusive data-structures as well.

Example from Windows:

http://msdn.microsoft.com/en-us/library/ms684121(VS.85).aspx


Take note of the node data-structure:

http://msdn.microsoft.com/en-us/library/ms686309(VS.85).aspx


They use no void* pointers, because the user could easily extend the
structure if they wish:

struct Custom_Node
{
SLIST_ENTRY SList_Node;
void* Object;
};
 
C

Chris M. Thomasson

spinoza1111wrote:
<snip>
And where, pray tell, are you going to *store* your elements?

In another object? Well, I personally enjoy embedding list nodes directly
into elements:
__________________________________________________________ [...]
__________________________________________________________

This way I do not have to allocate a seperate node to hold a pointer to
the
element. Humm... I think there are basically three ways to do this. [...]

A very good solution, but if you have multiple ways of chaining data
together, you're going to have to have arrays of nodes.

I am not exactly sure what you mean here. Could you elaborate?

And it doesn't
solve the problem addressed in C Unleashed which was to create a
reusable tool for handling linked lists.

I personally think that a reusable linked list should start out with an
intrusive design. This is the common denominator implementation. Then, you
would derive a non-intrusive design from it. Finally, you would derive an
implementation like Richards (e.g., value based) from the non-intrusive
design.


intrusive container
|
v
non-intrusive (void* pointer) container
|
v
value-based (copying) container



struct intrusive_node
{
struct intrusive_node* next;
};


struct non_intrusive_node
{
struct intrusive_node node;
void* object;
};


struct value_based_node
{
struct non_intrusive_node node;
size_t size;
};




You could derive more complex type that have constructors/destructors,
whatever... But since the base type is the good ol' intrusive node all very
basic list operations can be implemented at this low level.



You could write reusable software for handling pure node structs, but
that would necessitate a "callback" when you get to the problem of
comparing two linked lists for identity, or searching the list for a
value.

Well, usually the user would manually iterate the list and perform the
comparisons without using a callback function. I suppose I could use the
pre-processor to setup the compare functions on a per-type basis. Humm. Let
me think about it and I will post some example code.



The problem of linked lists is elegantly solved in your way in OO
code, since you can inherit a List and put your own data in it.

The problem is that Richard's "reusable" software only seems to have
considered one way, and this was a way that copies O(n) bytes and
creates the risk of having two copies of data. To be truly reusable it
needed to support three alternatives: linked list of copies, linked
list of pointers, or a pure linked list such as yours consisting only
of links to the next element (one with "null" data).
Agreed.




But this would have involved more advanced use of the preprocessor. My
complaint is the implicit presentation of only one way without
discussion of the alternatives, in the manner of the Fundamentalist
that Richard appears to be.

He presented one way to do it. That's fine. But I do think it would be nice
to explain all the other methods in detail.
 
S

spinoza1111

Ahh.

And so I see.

...

D'oh!  AND THE LIGHT GOES ON!

I think I have come to understand why it is thatspinoza1111has consistently
missed these things.

Have you ever noticed how some of his posts have quoted material ending with
something like "Show quoted text" or "read more"?

I betcha that, if you were to look at the posts in which I first pointed that
out in Google Groups, you might find that my explanations were *below* that
line.  And in general, he has consistently failed to respond to information
past that line, suggesting that he doesn't know how to show the rest of the
post.
No, by that time I'm usually fed up.

And nasty little clerks, who haven't been properly prepared for the
content of their job, tend to exagerrate nasty little clerical skills.

But, I ignore later material when I'm fed up. Which I am, usually,
with you.
Which might explain why he's never responded to or acknowledged the multiple
times I've said this.  But not all of them:

In other words "everybody be cool this is a robbery".

At the time the book was written, compiler writers often of their own
volition added "features" such as the assignment of meaning to <>. But
you didn't know that, did you. And you didn't care. Instead, you
harassed McGraw Hill at two removes from your narrow core competences.
You wrote as if you were knowledgeable about Microsoft platforms, and
you wrote as if you had yourself completed a computer science degree.

I do not know whether at the time Microsoft supported <>. But I do
know from working with John Nash at the time that its C compiler at
the time handled constant expressions idiomatically, such that his
code worked with Borland C and not Microsoft C. At the time of which
we write, the compiler was effectively the standard.

Your message misrepresented your actual standing, which was that of a
nasty little clerk.
 
S

spinoza1111

This brings up a vaguely topical question:

Can anyone name a dialect of C that has ever not supported variable
initialization?

As I have said, I don't know C as well as the regs. I'm just a better
programmer by several orders of magnitude.
MS is not famous for great compiler work, or for reasonable default
options.

It may not be famous, but they ship, and they pay their people in such
a way that even secretaries and orange badge temps can become
millionaires. They shipped Visual Basic when Bill Atkinson of Apple
couldn't be bothered to create a color version of Hypercard.

W3 as opposed to W4 is reasonable and follows the lead of most other
compilers, which don't get "picky" by default.
 
S

Seebs

Uh, no.
By the time the third edition of CTCR (the edition on which CTCN was
based) was written, the ANSI Standard was already six years old.

No, in 1995 (when CTCR3 was written), the ANSI C Standard was very
widely supported.

Exactly. The example's key error, which had nothing to do with the hilarious
(but typo-quality) error found in the 2nd edition, but fixed in the 3rd, was
a total failure to comprehend how sizeof() works.

-s
 
I

Ian Collins

Richard said:
Would that they did. Then the quality of software might improve a bit.

Why should they? If you want to analyse code, use a tool like lint.
Let the compiler focus on compiling legal code quickly and accurately.
 
N

Nick Keighley

Putting the bug aside, I had experience of people writing C like that
around 1990.  They'd been on some sort of course in some sort of
programming methodology (maybe SSADM, maybe not - it was a long time
ago).  In this case, they ended up writing something like:

a = fgets(buff, SIZE, stdin)
while(a) {
  do_things_with_a;
  a = fgets(buff, SIZE, stdin);

}

All perfectly logical, but utterly un-idiomatic and (particularly when
things were a bit more complicated) it led you to looking at the two
identical lines wondering if they were in any way different.

it's idiomatic in a language that doesn't allow assignment in the
test. Removing the duplicated line was one reason I liked C!
 
K

Keith Thompson

Ian Collins said:
Why should they? If you want to analyse code, use a tool like
lint. Let the compiler focus on compiling legal code quickly and
accurately.

Analysis tools *can* be distinct from the compiler, but they don't
have to be. There's no fundamental reason why a compiler can't do as
much analysis as it likes, perhaps optionally. Much of the analysis
is necessary for optimization anyway.

My understanding is that lint was originally implemented as a
separate tool (sharing some code with the compiler) because of
memory constraints.
 
R

Richard Tobin

There's no fundamental reason why a compiler can't do as
much analysis as it likes, perhaps optionally. Much of the analysis
is necessary for optimization anyway.

The reverse is also true: many useful warnings can only be generated
by doing (the equivalant of) optimisation.

-- Richard
 
B

Ben Bacarisse

Nick Keighley said:
On 23 Feb, 20:16, Nick <[email protected]> wrote:

it's idiomatic in a language that doesn't allow assignment in the
test. Removing the duplicated line was one reason I liked C!

It may be "idiomatic" but it is not good style in any language. If
you can't put an assignment in the test (because the language does not
allow it) then I think the way to go is an input function:

while (can_get_input(&a))
do_things_with(a);

Is there any language where you are forced to duplicate the input
line?
 
W

Willem

Ben Bacarisse wrote:
) It may be "idiomatic" but it is not good style in any language. If
) you can't put an assignment in the test (because the language does not
) allow it) then I think the way to go is an input function:
)
) while (can_get_input(&a))
) do_things_with(a);
)
) Is there any language where you are forced to duplicate the input
) line?

SQL, I think. In cursor fetch loops.


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 
E

Ersek, Laszlo

It may be "idiomatic" but it is not good style in any language. If
you can't put an assignment in the test (because the language does not
allow it) then I think the way to go is an input function:

while (can_get_input(&a))
do_things_with(a);

Or we could commit a little bit of style massacre:

for (;;) {
char buf[SIZE];

if (0 == fgets(buf, sizeof buf, stdin)) {
break;
}

/* ... */
}

Cheers,
lacos
 
W

Willem

Ersek, Laszlo wrote:
)> It may be "idiomatic" but it is not good style in any language. If
)> you can't put an assignment in the test (because the language does not
)> allow it) then I think the way to go is an input function:
)>
)> while (can_get_input(&a))
)> do_things_with(a);
)
) Or we could commit a little bit of style massacre:
)
) for (;;) {
) char buf[SIZE];
)
) if (0 == fgets(buf, sizeof buf, stdin)) {
) break;
) }
)
) /* ... */
) }

That's just plain silly; you moved the while() condition into an if()
condition with the exact same semantics.

I think you meant:

for (;;) {
a = fgets(...);
if (a == 0) {
break;
}
...
}

which could be even further massacred to:

do {
a = fgets(...);
if (a) {
...
}
} while(a);


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 
M

Moi

Ersek, Laszlo wrote:
) In article
<0.b03829bbcb6aa0133e99.20100224124328GMT.87zl2yls7j.fsf@bsb.me.uk>, Ben
is not good style in any language. If )> you can't put an assignment in
the test (because the language does not )> allow it) then I think the
way to go is an input function: )>
)> while (can_get_input(&a))
)> do_things_with(a);
)
) Or we could commit a little bit of style massacre: )
) for (;;) {
) char buf[SIZE];
)
) if (0 == fgets(buf, sizeof buf, stdin)) { ) break;
) }
)
) /* ... */
) }

That's just plain silly; you moved the while() condition into an if()
condition with the exact same semantics.

I think you meant:

for (;;) {
a = fgets(...);
if (a == 0) {
break;
}
...
}



do {
a = fgets(...);
if (a) {
...
}
} while(a);

which could be even further massacred to:

do {
a = fgets(...);
if (a) {
...
}
else continue;
} while(a);


AvK
 

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
474,109
Messages
2,570,671
Members
47,263
Latest member
SyreetaGru

Latest Threads

Top