Live data from Hacker News

Deconstructing "K&R C"

c.learncodethehardway.org

21–30 of 136 posts

Re: Deconstructing "K&R C"

#21
post #11
post #6

Earlier quoted context omitted.

No? It ensures that malloc didn't return a NULL pointer and the '&& "memory error"' is a common pattern to add a comment describing why an assert() statement failed.

One problem with it is that on most compilers if you compile with optimizations it will remove the assertion. Now the code is no longer guarded against malloc failures and will just segfault. If the intent is to teach people how to handle malloc failures gracefully, it's not that great of an example.

Why do you think the compiler with optimizations will remove the assertion?

The compiler will realise that:

    assert(assert(line != NULL && longest != NULL && "memory error");
Is equivalent to:

    assert(line != NULL && longest != NULL);
But there doesn't seem anything wrong with that.

Re: Deconstructing "K&R C"

#22
Guys, no need to jump all over this, clean code and defensive programming are solid practices to advocate. "That's just the way we do C" isn't really a good defense to someone trying to point out the warts in the way we do C, even if it did come from K&R.

Its easy to point to this for not sufficiently proving its argument, but its a work in progress, you're not the target audience, and finally, some of the shit in K&R seriously would not pass a code review here, and probably wouldn't where you work either.

Re: Deconstructing "K&R C"

#23
I think people are misunderstanding this; it's pedagogical. From the link:

'I want to use it as an exercise for you in finding hacks, attacks, defects, and bugs by going through "K&R C" to break all the code...When you are done doing this, you will have a finely honed eye for defect.'

He's trying to train his readers to think about places code can break.

Re: Deconstructing "K&R C"

#24

> Braces Are Free, Use Them I disagree. Braces have a cognitive load, particularly if they're given whole lines to themselves. Which is easier to read, while ((len = getline(line, MAXLINE)) > 0) if (len > max) { max = len; copy(longest, line); } if (max > 0) /* there was a line */ printf("%s", longest); or while ((len = getline(line, MAXLINE)) > 0) { if (len > max) { max = len; copy(longest, line); } } if (max > 0) /…

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.

Re: Deconstructing "K&R C"

#25
post #9

I don't see what the big deal is here. He throws inputs at a function not meant to handle them and gets a segfault. Isn't this more-or-less expected from all C functions? On careful examination of his example code, you can see that there's no attempt to terminate the buffer (though he misidentifies it as an "off by one" error). Throwing arbitrary buffers into functions meant for null-terminate strings will cause erro…

I don't see what the big deal is here. He throws inputs at a function not meant to handle them and gets a segfault. Isn't this more-or-less expected from all C functions?

We are getting separated from that kind of behavior. Nowadays the language is generally expected to protect you from yourself.

Re: Deconstructing "K&R C"

#26
post #11

Earlier quoted context omitted.

One problem with it is that on most compilers if you compile with optimizations it will remove the assertion. Now the code is no longer guarded against malloc failures and will just segfault. If the intent is to teach people how to handle malloc failures gracefully, it's not that great of an example.

Why do you think the compiler with optimizations will remove the assertion? The compiler will realise that: assert(assert(line != NULL && longest != NULL && "memory error"); Is equivalent to: assert(line != NULL && longest != NULL); But there doesn't seem anything wrong with that.

Production code is supposed to define away the assertions. It is an actual error to manage important program state with asserts.

(That doesn't make these particular asserts an error).

Re: Deconstructing "K&R C"

#27

> Braces Are Free, Use Them I disagree. Braces have a cognitive load, particularly if they're given whole lines to themselves. Which is easier to read, while ((len = getline(line, MAXLINE)) > 0) if (len > max) { max = len; copy(longest, line); } if (max > 0) /* there was a line */ printf("%s", longest); or while ((len = getline(line, MAXLINE)) > 0) { if (len > max) { max = len; copy(longest, line); } } if (max > 0) /…

We are talking abou K&R here. Please use the less spacious TrueBraceStyle instead of the heretic Allman style. :)

Joke aside, the problem I see in your argument is that lack of braces is also a cognitive load. If braces are always there I can safely ignore them but if they can be ommited I need to worry if a certain piece if code is braced or not when I read and edit it.

The only exception I currently live with is single line if statements, as long as the statement is on the same line as the `if`

Re: Deconstructing "K&R C"

#28

> Braces Are Free, Use Them I disagree. Braces have a cognitive load, particularly if they're given whole lines to themselves. Which is easier to read, while ((len = getline(line, MAXLINE)) > 0) if (len > max) { max = len; copy(longest, line); } if (max > 0) /* there was a line */ printf("%s", longest); or while ((len = getline(line, MAXLINE)) > 0) { if (len > max) { max = len; copy(longest, line); } } if (max > 0) /…

The middle version uses braces nicely to add whitespace to the function to help the reader flow through the code, instead of chasing matched-parens and wondering if each line is a continuation of the previous.

Re: Deconstructing "K&R C"

#29
post #9

I don't see what the big deal is here. He throws inputs at a function not meant to handle them and gets a segfault. Isn't this more-or-less expected from all C functions? On careful examination of his example code, you can see that there's no attempt to terminate the buffer (though he misidentifies it as an "off by one" error). Throwing arbitrary buffers into functions meant for null-terminate strings will cause erro…

I don't see what the big deal is here. He throws inputs at a function not meant to handle them and gets a segfault. Isn't this more-or-less expected from all C functions? We are getting separated from that kind of behavior. Nowadays the language is generally expected to protect you from yourself.

No, C is specifically for situations where you don't want the language to "protect you from yourself". E.g. systems programming where little or no runtime performance will be sacrificed to enable imperfect code to be safe.

Re: Deconstructing "K&R C"

#30
post #8

I'm confused. What is the "defect" in K&R's "copy(char to[], char from[])" function? The author notes that "the second this function is called...without a trailing '\0' character, then you'll hit difficult to debug errors", but no function with that signature could possibly work in this case. The built-in "strcpy" function has the exact same limitation. Does the author have a problem with it as well? Null-termination…

Huh? My C programming is in the distant past, so I might be forgetting. But strcpy does assume a terminal zero, doesn't it? E.g., http://linux.die.net/man/3/strcpy. It sounds like you are talking about strncpy or memcpy.
Post reply on HN