Live data from Hacker News

Humans should think of sizeof() as a function, says Linus Torvalds

lkml.org

121–130 of 140 posts

Re: Humans should think of sizeof() as a function, says Linus Torvalds

#121
post #92

Earlier quoted context omitted.

for, if, and while without curly braces for single statement blocks are easily one of the worst things about C. It bites you in the ass every time. The balance between its utility and its capacity to cause bugs is so one sided, I don't understand why it's even taught to beginners. If you are teaching a new programmer that saving keystrokes is important, you're on the fast track to creating a shitty programmer.

That's pretty severe. Written with spacing, its really pretty clear what is meant by if (condition) Foo(x) Braces are, in my opinion, an unfortunate necessity in some cases. They are a much larger cause of error than NOT using them ever could be. An ideal IDE would make blocking visible (background tone change etc), and braces could be emitted automatically by the IDE without ever cluttering up the code shown to the…

non-bracket is useful and informative in some cases when used properly (your local style guide takes precedence of course). I would never write

   if (condition)
      Foo(x)
for the reasons you said. But it can be very useful for a block of "single liners":

  /* clean up input before passing it to flaky_external_module() */

  for(; !isspace(*p); ++p); 
  if (!isdigit(*p)) return INPUT_ERR;
  for (char *i = p; *i; i++) *i = toupper(*i);
  ...

  flaky_external_module(p);

Basically a small block (that pretty much fits in your fovea) that does a bunch of minor tasks. Spacing them out would actually confuse the code.

Re: Humans should think of sizeof() as a function, says Linus Torvalds

#122
post #63

Earlier quoted context omitted.

And you really shouldn't use it with a type if you can avoid it anyway, it makes code brittle e.g. int *foo; // code foo = malloc(sizeof(int)); a few months later, change foo to be a double. Code still compiles, no warning, but you're allocating half the memory you need.

This is a really great example why you SHOULDN'T think of sizeof as a function. If sizeof were a function, the code int *foo = NULL; foo = malloc(sizeof(*foo)); would be undefined behavior (dereferencing NULL)!

Dereferencing a null pointer is legal in C. It's the conversion of a null pointer from from an r-value to an l-value that's illegal, which does not happen in that snippet of code.

That's why it's perfectly legal in C to do this (&*foo), even if foo is a null pointer.

Re: Humans should think of sizeof() as a function, says Linus Torvalds

#123
post #122
post #63

Earlier quoted context omitted.

This is a really great example why you SHOULDN'T think of sizeof as a function. If sizeof were a function, the code int *foo = NULL; foo = malloc(sizeof(*foo)); would be undefined behavior (dereferencing NULL)!

Dereferencing a null pointer is legal in C. It's the conversion of a null pointer from from an r-value to an l-value that's illegal, which does not happen in that snippet of code. That's why it's perfectly legal in C to do this (&*foo), even if foo is a null pointer.

> Dereferencing a null pointer is legal in C. It's the conversion of a null pointer from from an r-value to an l-value that's illegal, which does not happen in that snippet of code.

And it does not happen in that snippet of code because sizeof is nothing like a function.

Re: Humans should think of sizeof() as a function, says Linus Torvalds

#124
post #121

Earlier quoted context omitted.

That's pretty severe. Written with spacing, its really pretty clear what is meant by if (condition) Foo(x) Braces are, in my opinion, an unfortunate necessity in some cases. They are a much larger cause of error than NOT using them ever could be. An ideal IDE would make blocking visible (background tone change etc), and braces could be emitted automatically by the IDE without ever cluttering up the code shown to the…

non-bracket is useful and informative in some cases when used properly (your local style guide takes precedence of course). I would never write if (condition) Foo(x) for the reasons you said. But it can be very useful for a block of "single liners": /* clean up input before passing it to flaky_external_module() */ for(; !isspace(*p); ++p); if (!isdigit(*p)) return INPUT_ERR; for (char *i = p; *i; i++) *i = toupper(*i…

I contend that the brackets always make the code more readable, without exception. It's the normal case. All other variations make you think "something special is happening here, I'm going to have to parse this carefully". The for with a semicolon at the end is easy to overlook. The return in the middle of a function in the middle of a line is easy to overlook.

Spacing code out makes it more readable and maintainable, not less. It brings consistency, and it is more prepared for the inevitable change. I think maintenance is the driver of all code style. When you make tight one liners or forgo braces, or use the ? And : operators instead of if and else, you're not really saving time, you are deferring work, in a lot of cases to another programmer.

Re: Humans should think of sizeof() as a function, says Linus Torvalds

#125

Yes, return can be a function. Torvalds hasn't heard of continuations, obviously, where we "return" from a function by invoking a continuation. We can justify writing return (expr); using the same arguments that justify the sizeof (expr) convention. The thing is that in C , return isn't a function; there are no continuations. Similarly, sizeof is an operator, which doesn't reduce its argument expression to a value. I…

He is talking about C. Continuations are irrelevant.

That point is clearly made in the comment you're replying to, with the additional point that if we are talking about C, then sizeof is an operator, not a function. It doesn't require parentheses, except when its operand is a type expression. No well-considered coding convention requires superfluous parentheses with sizeof, and there are good reasons to ban them.

We should prefer code like:

   type *ptr = malloc(sizeof *ptr);  /* no parens */
to

   type *ptr = malloc(sizeof (type));
In general it's often better to base sizeof on an ordinary expression rather than a type expression.

If we don't use superfluous parentheses on sizeof, we can then look for sizeof followed by an open parenthesis to look for code where sizeof is applied to a type expression.

  sizeof (type)
means "produce me a size_t value based on some arbitary type, without checking that it's related to anything in the surrounding code". It can be as dangerous as a (type) cast.

Re: Humans should think of sizeof() as a function, says Linus Torvalds

#126

Earlier quoted context omitted.

He literally says that those who disagree with his code style should be shot. That's completely unacceptable language to use and makes him sound like he hasn't mastered English. I'm not sure anyone should take c-language style tips from such a boor.

It's called hyperbole, it's quite common in english.

[deleted]

Re: Humans should think of sizeof() as a function, says Linus Torvalds

#127
post #52

Earlier quoted context omitted.

And you really shouldn't use it with a type if you can avoid it anyway, it makes code brittle e.g. int *foo; // code foo = malloc(sizeof(int)); a few months later, change foo to be a double. Code still compiles, no warning, but you're allocating half the memory you need.

Which is why it's nice to lift stuff out into typedefs. It centralizes them (DRY principle) and avoids this issue. typedef int thing_t; ... thing_t *foo; // code foo = malloc(sizeof(thing_t));

As an aside, I think nearly any time you want a typedef, it's worth wrapping it in a struct.

    typedef struct { int value; } thing_t;
That way the compiler catches it when you try to pass the wrong thing (at least, more of the time).

Re: Humans should think of sizeof() as a function, says Linus Torvalds

#128
post #52

Earlier quoted context omitted.

And you really shouldn't use it with a type if you can avoid it anyway, it makes code brittle e.g. int *foo; // code foo = malloc(sizeof(int)); a few months later, change foo to be a double. Code still compiles, no warning, but you're allocating half the memory you need.

Which is why it's nice to lift stuff out into typedefs. It centralizes them (DRY principle) and avoids this issue. typedef int thing_t; ... thing_t *foo; // code foo = malloc(sizeof(thing_t));

DRY is good, but making the structure of your code reflect the actual semantics you want is better. What you want is to allocate space for foo. So write that.

Re: Humans should think of sizeof() as a function, says Linus Torvalds

#129
post #117

Earlier quoted context omitted.

I hear folks say that, but don't encounter it in the wild. Maybe once in 20 years so far. That construct, reading it just now, just screams out at me "Indentation error!" Anyway it nicely illustrates the need to get braces out of there altogether. The programmers' intent is obvious; let the IDE 'make it so' by emitting braces in the generated code.

I've never seen (in code I've worked on) if (condition) Foo(x); Bar(x); But I have seen if(condition1) if(condition2) if(condition3 && condition4) Foo(); This upset the old ARM compiler I was working on and it decided to skip some of the conditions. I fixed the bug, related to this code, by adding braces: if(condition1) { if(condition2) { if(condition3 && condition4) { Foo(); } } } So this is why I always put braces…

"This upset the old ARM compiler I was working on and it decided to skip some of the conditions."

Do what you need to work around a known compiler bug, of course, but that is definitively a compiler bug. The meaning is unambiguous and consistent in the C standard and every implementation I've encountered. I'm not comfortable with the assertion that changing your coding style here makes you less susceptible to compiler bugs in general.

Re: Humans should think of sizeof() as a function, says Linus Torvalds

#130
post #71
post #44

Earlier quoted context omitted.

it looks quite disturbing without them Remove the newline and it looks ok to me: int i = 42; do printf("hey\n"); while (--i > 0); Another possibility would be: int i = 42; do printf("hey\n"); while (--i > 0);

Just looking ok is not the point. I would prefer a match between how it looks and what it does...

I agree, but I don't see that undermined here.
Post reply on HN