Live data from Hacker News

Deconstructing "K&R C"

c.learncodethehardway.org

111–120 of 136 posts

Re: Deconstructing "K&R C"

#111
post #7
post #4

Isn't "assert(line != NULL && longest != NULL && "memory error");" a bug in Zed's example code?

I think you're mentally substituting "&&" with "||", in which case the assert would never fail because the string "memory error" is never 0. But with &&, the assert will fail when it should and the "memory error" is just a superfluous comment, not a bug.

That's absolutely correct, thanks for pointing that out.

Re: Deconstructing "K&R C"

#112
post #80

Earlier quoted context omitted.

It's a nice strawman, right? Especially when he points out that the original code, in context, is perfectly fine. His later complaint about the assignment-in-if statement is certainly something shared by modern C programmers (see compiler warnings about same), but it perfectly fits the original style and accomplishes its task. His criticisms seem to be rooted so far in stylistic issues and in taking the code out of c…

My criticisms are only partially stylistic, but also that people copy this code to other situations and it breaks. So, I'm showing them why it only works in that one specific context and how to break the code.

If I can make a suggestion, then. I apologize if you've already covered this elsewhere in your book, but:

Please encourage the use of the "restrict" keyword to encourage proper aliasing optimization by compilers.

Also, would it be worth considering, perhaps in a chapter on how-to-deal-with-C-style-strings-if-you-must, including a section on writing compiler-independent macros to emulate safer calls like the str*_s variants in VS. These functions are usually slightly-different in incantation across VS and GCC, so it might be helpful to abstract them. It also is a relatively simple exercise in preprocessor macros with a clear benefit.

Re: Deconstructing "K&R C"

#113

Earlier quoted context omitted.

The string data type in the db? Because Redis itself uses char-stars all over the place, with the libc string functions.

Hmm, reading the source it looks like he is using His sds string library, which has Len, size and a asciiz char* member. When last I checked he does pass the char* around (because it is null terminated) but he also sometimes will do pointer math to get back to the sds

You're right; I was reacting to the count of char\s+star and snprintf calls, but only fair to chalk Redis up among the packages I have that rely on a high-level string library.

Re: Deconstructing "K&R C"

#114
post #85

Earlier quoted context omitted.

Noble goal, but the way the chapter is written doesn't really come across that way, in my opinion.

Speaking as someone who doesn't know C, hasn't read K&R, but who (usually!) has decent reading comprehension, it _does_ come across this way. He's completely explicit about what he's doing and why. I don't understand how people can read that and still feel that he's being unfair. Maybe I'm just too literal-minded.

Calling string manipulation functions buggy and broken because they fail when you don't pass them a string is both wrong and silly.

Re: Deconstructing "K&R C"

#115
post #55

Earlier quoted context omitted.

Dated, buggy, and un-stylish examples are exactly what diminishes it.

And those dated, buggy, and unstylish examples would be?

I dug out my 29th printing copy for this :)

Dated: the "Hello world" on page 6 produces warnings when compiled "> gcc -ansi -o hello hello.c -Wall" c.f. http://c-faq.com/ansi/maindecl.html

Buggy but only to a pedant with infinite time: the word count on page 18 that uses a `double` which will run out of accuracy once you count more words than there are atoms in the universe. ( `double toot = 1000000000000000000; toot++;` what is the approximate value of toot?)

Buggy by omission: Section 5.5 (on page 104) doesn't really go into the hazards of C strings, and the text's implementation of strcpy when using strings from unfriendly places (public wifi, quicktime files) can turn the interesting kind of nasty if you hammer on it enough.

Unstylish: brace-less if statements in many examples; a two-line one on page 110, for example.

I worked as a contractor in a C shop for several months a few years back, and I kind of see what happens when you code K&R-style instead of extremely defensively and conservatively. For example, the strcpy on page 106 is cute, but is it going to be as maintainable as the naïve version the previous page, or the hypothetical (unless I just failed to find it) LCTHW known-length string copy function?

Re: Deconstructing "K&R C"

#116
post #114

Earlier quoted context omitted.

Speaking as someone who doesn't know C, hasn't read K&R, but who (usually!) has decent reading comprehension, it _does_ come across this way. He's completely explicit about what he's doing and why. I don't understand how people can read that and still feel that he's being unfair. Maybe I'm just too literal-minded.

Calling string manipulation functions buggy and broken because they fail when you don't pass them a string is both wrong and silly.

How do you test that something in C is a string?

Re: Deconstructing "K&R C"

#117
post #78

Earlier quoted context omitted.

I'm probably the last person in the world to prefer: while ((len = getline(line, MAXLINE)) > 0) if (len > max) { max = len; copy(longest, line); } if (max > 0) /* there was a line */ printf("%s", longest); I fear this may be literally true: this brace style is called Whitesmith's, and I was reporting bugs to the cc-mode indenter for emacs a while ago. BSD/Allman and K&R styles never made sense to me.

Add a new statement to the while-loop. Now you've figured out why that style isn't so hot. You now have to remember to go add the new braces, and typically people are mentally putting them in so they forget. Same with the last if-statement. You'll go, add the new line, indent and go "cool done". Then scratch your head for hours wondering why it's not working.

Exactly. Fully bracketed syntax prevents this kind of maintenance breakage.

Weird contrast: Perl, for all its klugy syntax, requires fully bracketed syntax on the statement bodies of "if", "while" & the like, so this never happens. Of course, you get other readability issues there...

Re: Deconstructing "K&R C"

#118
post #79
post #53

Earlier quoted context omitted.

It's way worse than an extra byte, or the offset of 1 byte for pointers; it also means you need a whole copy of every substring with its own length delimiter, and can't tokenize in place. C code gets into just as much trouble with length-delimited data structures as it does with ASCIIZ; ASCIIZ is a red herring. People have declared over and over again that it's the single worst decision in C and the cause of every bu…

I partially agree with you, but in a different way. I feel that the real problem is the OS doesn't give code access to its own internal accounting of allocated memory. It already knows the size of any heap chunk you make, so why can't we ask it? In most C code we're carrying around either a null terminator (which can get clobbered) or a whole integer for the size. Instead, there should be a way to ask the OS "how big…

That's a hell of a good idea. As somebody pointed out, it might not stop you from corrupting neighboring items in an array or structure, but it would let you find the size of an array allocated by itself, AND, it would stop you from corrupting the heap itself!

Re: Deconstructing "K&R C"

#119
post #53

Earlier quoted context omitted.

"Yes, there are problems with the whole approach of using a terminating value" And, of course, there are problems with the other approaches too. Using a single length byte at the beginning limits you to 255 characters and makes pointer manipulation less straightforward (since the actual data starts one byte further on). Using more than one byte for the string length wastes space (a serious issue at the time C was dev…

It's way worse than an extra byte, or the offset of 1 byte for pointers; it also means you need a whole copy of every substring with its own length delimiter, and can't tokenize in place. C code gets into just as much trouble with length-delimited data structures as it does with ASCIIZ; ASCIIZ is a red herring. People have declared over and over again that it's the single worst decision in C and the cause of every bu…

I would happily trade C ASCIIZ strings for Pascal/Perl/Java out of band length indicated strings, even at the cost of those edge cases. Especially if there were a way to internalize immutable string data, and share the bytes of common fragments. (this of course doesn't work well if you plan on modifying the string data)

Re: Deconstructing "K&R C"

#120
post #55

Earlier quoted context omitted.

And those dated, buggy, and unstylish examples would be?

I dug out my 29th printing copy for this :) Dated: the "Hello world" on page 6 produces warnings when compiled "> gcc -ansi -o hello hello.c -Wall" c.f. http://c-faq.com/ansi/maindecl.html Buggy but only to a pedant with infinite time: the word count on page 18 that uses a `double` which will run out of accuracy once you count more words than there are atoms in the universe. ( `double toot = 1000000000000000000; toot…

1. You're singling out the first "hello world" program in the book which is making an effort to show C using the fewest concepts necessary; flip elsewhere in the book and notice the other main() functions return int values. (The default "int" is C89; the "warning" is for C99; the second edition of K&R is ANSI C89, not C99).

2. First the nit misses the spirit of the example which is simply to demonstrate that "double" has higher precision than the fixnum "long" type; second, calling it a bug misses the fact that text explicitly does not say you can use it to count arbitrary strings; as the text says, it depends.

3. You're calling "buggy by omission" an implementation of strcpy not substantially different from BSD's libc. K&R's is, in fact, how you would write strcpy(). That strcpy() doesn't handle hostile strings is irrelevant; you're not intended use strcpy() on hostile strings.

4. Hard to fathom how one criticizes a book on C for braceless "if"s. We could go toe to toe on high-quality C programs and whether they ever use them; nginx, for example, avoids them; dovecot doesn't. Both are exceptionally high quality C codebases.

Not that you have anything to prove to me, but I reject all your examples, and think you were too cavalier about judging K&R.

But I appreciate the response (and thus the opportunity to piously respond to it). :)

Post reply on HN