
Humans should think of sizeof() as a function, says Linus Torvalds - arjun024
https://lkml.org/lkml/2012/7/11/103
======
krylon
IIRC, if the argument to sizeof is a type, the parentheses are mandatory,
anyway, so using it like it was a function is more consistent.

I think the reason it is not a function from the standard's point of view is
that C does not have any builtin functions (unless my memory totally fails me
in this case), all functions have to be either defined locally or #included.

~~~
barrkel
Another oddity of C that amuses me is the do/while loop without braces:

    
    
        int i = 4;
        do
           printf("hey\n");
        while (--i > 0);
    

Even though do/while is a keyword bracketing pair in C, it still only lets you
use a single statement (because nested whiles). So everybody uses braces, and
thus it looks quite disturbing without them.

~~~
cygx
_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);

~~~
viraptor
Oohh... this would be so good for the underhanded C contest! Just mix is up
with the comments which make the `do` look like (assuming good actor) an
accidentally wrapped comment.

    
    
        /* The following code does something, so here's the
        // explanations of what happens. And here's what we actually
        */ do
        printf("hey\n");
        
        /* And now just count down */
        while (some_check(--i));
    

Now spot that in a large file of real code!

~~~
pierrec
Sneaky. Most syntax highlighting would make it stick out like a sore thumb,
but still, sneaky.

------
Udo
I'd like to confess that I'm one of the return() people, and I also do if()
even in cases where the language doesn't require it. This behavior isn't borne
out of confusion about what is and what isn't a special language construct.
Rather, it helps me prop up the illusion that programming is about using a few
simple primitives instead of being the chain of compiler directives it
actually entails - it's an esthetic choice if not always a logical one.

The thought that if() _could_ just be a lazily-evaluated function taking a
code block argument, and that return() _could_ be a way of marking the end
result of an expression somehow pleases me.

I think the different expectations about sizeof() come from the artificial
distinction between operators and functions, the implication being that in a
compiled language the sizeof operator would be a compile-time construct, or
barring that, at least a behavior of the type system. On the other hand, there
are tons of compiler intrinsics in C/C++ that look exactly like functions but
aren't.

~~~
sedeki
Doesn't `if` always require parenthesizes?

~~~
nikai
Not even in C. You can have an if condition that is actually a macro that
expands with parentheses. For example the macros in ctype.h, so you can
actually write

    
    
      if islower(c) {
          (..)
      }

~~~
cygx
That's not portable, though: A comforming implementation may very well
implement _islower_ as a function call, and you should treat is as such.

------
Negative1
I respect Linus greatly but the way he to talks to his fellow 'humans' is
insanely confrontational, rude and disrespectful. It overshadows his arguments
(which are usually very good) and throws people on the defensive. I'm grateful
for all he has accomplished and shared with us but I imagine working with him
is 'hell'.

~~~
topkekz
[http://www.catb.org/esr/faqs/smart-
questions.html#keepcool](http://www.catb.org/esr/faqs/smart-
questions.html#keepcool)

~~~
mcguire
Keep in mind: that's the dipshit that thinks he's the avatar of Pan.

------
gpvos
I used to write

    
    
        return (0);
    

I.e., with a space. I'm not sure if someone ever told or recommended me to do
this, but the reason I did this was consistency with other C statements,
because _all_ C statements that take some kind of expression as a parameter
(if, for, while) require it to be surrounded by parentheses. So it seemed
logical to me to do the same with return. I've stopped doing it now, although
some of the old code still lives.

I've seen code by others where there was always a space between the function
name and its arguments. _That_ was ugly, and really confused a function call
with a statement.

~~~
krylon
I find parens around a return value/expression slightly annoying, but not
annoying enough to have a debate over it. It doesn't make the code harder to
read, IMHO.

Whitespace between a function name and the arguments _is_ significant,
however, because with a function-like macro, there must be _no_ whitespace
between the name and the opening parenthesis. I've seen the following code in
production code, for example:

    
    
      #include <stdlib.h>
      #define free(x) free(x), x = NULL
    
      free(ptr1); // Macro
      free (ptr2); // Call free(3) directly
    

(Whether or not such a macro is good idea is a different question entirely,
the point is that you can prevent such macro-expansion by using whitespace.
Aesthetically, I find it very disturbing, though.)

~~~
rwallace
You do need to omit whitespace between the name and the opening parenthesis
when defining a functionlike macro, but it doesn't matter when you're calling
it.

~~~
krylon
I furiously looked at the C standard (C99, anyway) and the documentation to
the gcc preprocessor, and have to admit somewhat embarassedly, that you are
right. The gcc preprocessor documentation clearly states:

> "If you use the macro name followed by something other than an open-
> parenthesis (after ignoring any spaces, tabs and comments that follow), it
> is not a call to the macro, and the preprocessor does not change what you
> have written."

Thanks for pointing this out to me!

------
moonbug
"Quite frankly, if you do this, you should be shot. "

Ah, yes. No comment from Torvalds is complete without a gratuitous ad hominem.

~~~
loup-vaillant
This is not an ad hominem argument. This is merely blowing things out of
proportion. _This_ would be ad hominem (and non-sequitur):

"You're watching dancing bunnies, and you _dare_ suggest we should remove the
parens after sizeof?"

Attack on the person (watching dancing bunnies), used to discredit an
unrelated opinion (parens after sizeof).

------
Chathamization
I first learned that sizeof was an operator when I was confused about how it
dealt with arrays compared to functions. After I learned it was an operator
and not a function things made sense and were (relatively) consistent again.
Several commentators here have given other examples where you will be
completely thrown off if you believe that '"sizeof()" really _is_ a function.'

The problem with "lies to children" is that they can pile up to the point
where people end up becoming completely confused about what's actually
happening. As the internal inconsistencies mount, the "simple" lie starts to
become a lot more complex than the "complicated" truth.

------
tvb
Makes a good C interview question:

    
    
        char  c;
        short h;
        int   i;
        char *s;
        1 = sizeof (char)
        2 = sizeof (short)
        4 = sizeof (int)
        4 = sizeof (float)
        8 = sizeof (double)
        1 = sizeof (c)
        2 = sizeof (h)
        4 = sizeof (i)
        4 = sizeof (s)
        4 = sizeof &c
        1 = sizeof c
        2 = sizeof h
        4 = sizeof i
        4 = sizeof s
        1 = sizeof *s
        4 = sizeof &main
        4 = sizeof (sizeof (i))
        4 = sizeof (sizeof i)
        4 = sizeof sizeof i
        4 = sizeof sizeof sizeof i
    

from:
[http://leapsecond.com/tools/size1.c](http://leapsecond.com/tools/size1.c)

------
nmj
> Here's an example of a really bad use of "sizeof" that doesn't have the
> parenthesis around the argument: sizeof(*p)->member. Quite frankly, if you
> do this, you should be shot.

Good ol' Linus

~~~
thomasahle
I certainly read that the wrong way first time around.

------
mburns
(2012)

------
mattkrea
Just as annoying as people not using parens with "typeof()" in JavaScript.

------
tormeh
Why is this important?

------
wz1000
> "return()" is in no way a function.

Ah, but in Haskell, `return` is a function, though it shares only a few
similarities with with its counterpart in C-like languages.

However, when using continuations or a continuation passing style, the
continuation is a function that behaves almost exactly like traditional return
when called!

    
    
        (define (multiply x y return)
          (return (* x y)))

~~~
wz1000
Was there something factually incorrect in my comment?

~~~
stonogo
Was there something _relevant_ in your comment?

~~~
wz1000
I was pointing out that if you can consider sizeof a function, you can
consider return one too.

------
progrn
But, I cannot get a function pointer to it, right?

~~~
fnthrowa98
It is a function in the mathematics sense, not the C sense.

------
soup10
What kind of monsters don't use parentheses on sizeof. Is it the same guys
that put { on new lines and have giant comment templates for every one line
function.

~~~
MrBuddyCasino
Ah, to join the bikeshedding: { on newlines make imho more sense, the block of
code is visually balanced that way. We have high-res screens now, no reason to
pretend we're still on 80 char terminals.

But work long enough in either one of those styles, and the other one will
start to look strange.

~~~
Retra
What advantage does 'visually balanced' give? That's like saying the letter A
is better than B because it's 'stands up better.'

Indentation is how you should identify blocks.

~~~
xamuel
Indentation to identify blocks can break down in things like switch
statements:

switch( c ) {

    
    
       case 'A':
         simple_stuff();
         break;
    
       case 'B': {
         int temporary_variable = 0;
         complex_stuff( temporary_variable );
     }
    

To me, the advantage of braces on newlines is it makes it extremely easy to
tell where blocks start and end---whether you're using your favorite IDE, or
reading the code on a blog, or reading the code with "cat". I actually think
it's a case where Python has the design advantage on C (since if you do
braces-on-newline consistently enough, you end up duplicating python but with
superfluous braces added in).

~~~
douche
I'm not seeing what the issue here is, besides that this won't compile because
of mismatched braces. There is no need to put braces around the contents of a
case block. Unless I'm switching on an enum, I rarely find a compelling reason
to use switch/case, and there's usually a cleaner way to do it.

~~~
dllthomas
_" There is no need to put braces around the contents of a case block."_

There is here.

In some dialects, you can only declare a variable at the start of a block.
From the perspective of the compiler, a "case block" isn't actually a block,
just stuff between labels. In order to declare temporary_variable, it may be
necessary to put the braces, and it is probably best practice as
temporary_variable may otherwise be exposed to later cases (and in C++, a jump
over a variable declaration seems to produce an error).

------
lazzlazzlazz
Who the hell doesn't think of `sizeof` as a function?

~~~
noselasd
It's an unary operator, with 2 forms:

    
    
       sizeof(type)
    

or

    
    
      sizeof expression
    

but e.g. unlike a function, it doesn't evaluate the expression.

    
    
        sizeof(my_function()) doesn't call my_function.
    
        sizeof(a = 12) doesn't assign 12 to a.

~~~
Retr0spectrum
So is "sizeof(a = 12)" equivalent to just "sizeof(a)"?

~~~
hebdo
Well, `a` could overload the "=" operator, in which case you would get
`sizeof(a.operator=(12))`. But as far as pure C goes I believe you are right.

Edit: Via the C99 spec ([http://www.open-
std.org/jtc1/sc22/WG14/www/docs/n1256.pdf](http://www.open-
std.org/jtc1/sc22/WG14/www/docs/n1256.pdf)).

 _The sizeof operator yields the size (in bytes) of its operand, which may be
an expression or the parenthesized name of a type. The size is determined from
the type of the operand. The result is an integer. If the type of the operand
is a variable length array type, the operand is evaluated; otherwise, the
operand is not evaluated and the result is an integer constant._

 _The type of an assignment expression is the type of the left operand unless
the left operand has qualified type, in which case it is the unqualified
version of the type of the left operand._

So it is indeed the case that `sizeof(a = 12)` is equivalent to `sizeof(a)` in
the C world.

~~~
to3m
An interesting result of this (I suppose...) is that if a macro expands an
argument twice, and one of those times is an operand for sizeof, you don't
need to mention the double expansion in the documentation.

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

If we are going to make coding conventions based on pretending that C is a
different language in which sizeof is a function, then pretending return is a
function is also fair game.

~~~
hueving
He is talking about C. Continuations are irrelevant.

~~~
kazinator
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.

