|
|
Log in / Subscribe / Register

Quotes of the week

-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])		      \
+	+ sizeof(typeof(int[1 - 2*!!__builtin_types_compatible_p(typeof(arr), \
+		 typeof(&arr[0]))]))*0)

-- Rusty Russell

Rusty, that's a work of art.

However, I would suggest that you never show it to anybody ever again. I'm sure that in fifty years, it will be worth much more. So please keep it tightly under wraps, to keep people from gouging their eyes out^W^W^W^W^W^W^W make a killing in the art market.

-- Linus Torvalds


to post comments

See it evolve

Posted Mar 15, 2007 6:05 UTC (Thu) by proski (guest, #104) [Link] (1 responses)

If you see the thread, this monster evolves into something quite comprehensible. The new implementation reuses an existing macro and provides a macro that could be reused by others.

See it evolve

Posted Mar 15, 2007 12:22 UTC (Thu) by nix (subscriber, #2304) [Link]

What do you mean? It was perfectly comprehensible already.

;}

Quotes of the week

Posted Mar 15, 2007 6:29 UTC (Thu) by martin@zeroscale.com (guest, #5376) [Link] (21 responses)

Please explain! What does it do? Is Linus being ironic or is the piece of code superb?

Quotes of the week

Posted Mar 15, 2007 8:32 UTC (Thu) by HenrikH (subscriber, #31152) [Link] (1 responses)

Linus is as ironic as always, if you read the thread you will find a later comment from him that is more to the truth:

"Well, since Rusty's macro was hoddible *anyway*, I don't think I'd apply
it as-is. Breaking icc for something that ugly and not-very-important
simply makes no sense.
"

Quotes of the week

Posted Mar 15, 2007 12:01 UTC (Thu) by k8to (guest, #15413) [Link]

Given how Rusty's submission was couched "here's a special gcc thing we don't use yet" I presumed it was a joke. Wrong.

The eventual implementation is good style. The names of the pieces clearly say what they do, and are bite sized enough that you can confirm them. The first take was pretty WTF.

Quotes of the week

Posted Mar 15, 2007 12:33 UTC (Thu) by nix (subscriber, #2304) [Link] (18 responses)

It's quite nifty.

Breaking it down:

#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])

This was the original. It works fine if arr is an array, but if it's a pointer, it'll return rubbish. (This is the one situation in which the decay of arrays to pointers is detectable. Obviously declaring a parameter using the [] syntactic sugar, e.g. char *argv[] doesn't help; it's still a pointer, not an array.)

The rest makes sense if you read it from the inside out (as is so often the case with C, and, for that matter, with bracketed expressions anywhere).

!!__builtin_types_compatible_p(typeof(arr), typeof(&arr[0]))

__builtin_types_compatible_p returns 1 if two types are compatible and 0 otherwise. This compares the type of arr to the type of the address of its first element (guaranteed to be a pointer even if the original was an array). It gets !!ed to ensure that the result is specifically 0 or 1 (GCC guarantees that in the docs right now, but it's easy to envisage a situation in which it returned 0 or some nonzero value. This guards against that happening.)

So now we need to arrange for that 1 value to lead to some sort of compiler warning.

sizeof(typeof(int[1 - 2*!!__builtin_types_compatible_p(typeof(arr), typeof(&arr[0]))])*0)

The bit inside the square brackets yields 1 if the types are incompatible (1 - 2*0) and -1 if it isn't. int[1] is a valid type; int[-1] isn't, and the compiler warns if you try to take its size; and that'll happen if arr is of a type compatible with a pointer (but not if it's an array).

Then the multiplication by zero eliminates any actual non-warning effects of all this code.

Quotes of the week

Posted Mar 15, 2007 14:46 UTC (Thu) by a9db0 (subscriber, #2181) [Link]

Thank you for that intelligent explanation of Rusty's gobbledygook. Makes much more sense now.

Dave

Quotes of the week

Posted Mar 15, 2007 16:07 UTC (Thu) by tjc (guest, #137) [Link]

This is the one situation in which the decay of arrays to pointers is detectable. Obviously declaring a parameter using the [] syntactic sugar, e.g. char *argv[] doesn't help; it's still a pointer, not an array.
It's pretty inconsistent syntactic sugar at that. It's interesting that void f1(int *foo) is the same as void f1(int foo[]), but int *f2(void) is not the same as int f2(void)[].

Quotes of the week

Posted Mar 15, 2007 19:55 UTC (Thu) by gravious (guest, #7662) [Link] (15 responses)

Hats off - I looked at the !!blah stuff and my Java - it's a work thing :( - infected brain couldn't parse it. Bah - and to think I used to be able to grok quite convoluted expressions. 0 -> 1 -> 0 . n -> 0 -> 1 . Cool. Of course it didn't help that I was trying to guess the logic and side effects of __builtin_types_compatible_p(a,b) from the (scary) context. Which is why I'm not a kernel dev as well I guess!

Grokking convoluted expressions

Posted Mar 16, 2007 9:59 UTC (Fri) by ldo (guest, #40946) [Link] (14 responses)

I'm quite proud of this one, though it's probably not original. :)

Grokking convoluted expressions

Posted Mar 16, 2007 10:31 UTC (Fri) by nix (subscriber, #2304) [Link] (10 responses)

I don't know, I've never seen anything quite like it. Operator mangling like that is fairly unusual in C because nobody can remember the precedence rules :)

Grokking convoluted expressions

Posted Mar 17, 2007 12:58 UTC (Sat) by Tet (subscriber, #5433) [Link] (4 responses)

I thought everyone knew the rules for operator precedence in C and C-like languages: * and / bind more tightly than + and -, and everything else gets parentheses :-)

(My Google-fu is letting me down, and I can't find the original author of that quote)

Grokking convoluted expressions

Posted Mar 17, 2007 16:28 UTC (Sat) by nix (subscriber, #2304) [Link] (3 responses)

Yeah, exactly. It really gets confusing when *, ->, [], &, &&, and
arithmetic operators all come and play together.

Grokking convoluted expressions

Posted Mar 17, 2007 18:38 UTC (Sat) by tjc (guest, #137) [Link] (2 responses)

It really gets confusing when *, ->, [], [snip] and arithmetic operators all come and play together.
Things would be simpler if *, both as a pointer declarator and as the dereference operator, were postfix (and as a consequence left-to-right associative, with the precedence level incremented by one). It looks weird, but that's mostly because we're not use to seeing it that way. It would be also consistent with the use of [].

For example, the signal function would then be:

void signal(int signum, void handler*(int)) *(int);

...which is a bit easier to untangle than the way it really is:

void (*signal(int signum, void (*handler)(int))) (int);

That would also eliminate the need for ->, since one could just do this:

foo*.bar

...which is consistent with:

foo[0].bar

Of course there's no need for -> anyway, since there's no ambiquity between struct_var.foo and pointer_var.foo -- taking the member of a pointer doesn't make sense, so there's no need for a special operator. The compiler could just take care of this for us.

It's probably too late to change. :-)

Grokking convoluted expressions

Posted Mar 18, 2007 1:53 UTC (Sun) by nix (subscriber, #2304) [Link]

This is of course exactly what Pascal, Ada and other related languages do
with ^. It *does* make more sense than the alternatives, but there's no
chance of changing now :( hell, the precedence rules couldn't be changed
when C was less than three years old (when && and || were introduced...
with the wrong precedences for compatibility reasons), so I doubt a whole
new operator could be introduced now :)

Grokking convoluted expressions

Posted Mar 24, 2007 5:21 UTC (Sat) by RareCactus (guest, #41198) [Link]

Of course there's no need for -> anyway, since there's no ambiquity between struct_var.foo and pointer_var.foo -- taking the member of a pointer doesn't make sense, so there's no need for a special operator. The compiler could just take care of this for us.

It's probably too late to change. :-)

Having the language infer what you mean to do by the context is often a bad idea. If people want to dereference a pointer, they should use the dereference operator, not just silently have the language fill that in.

And yes, the syntax of function pointers is fubar in C.

Grokking convoluted expressions

Posted Mar 17, 2007 22:38 UTC (Sat) by ldo (guest, #40946) [Link] (4 responses)

Operator mangling like that is fairly unusual in C because nobody can remember the precedence rules :)

Yeah, that's why I included the parenthesis-riddled version.

But then, why do you need to remember? I keep a copy of K&R 2nd ed where I can reach it without leaving this chair, just so I can look up finer points like this.

For everybody else, I've put together this page. :)

Grokking convoluted expressions

Posted Mar 19, 2007 15:03 UTC (Mon) by tjc (guest, #137) [Link] (2 responses)

For everybody else, I've put together this page. :)
A very useful page, but shouldn't the type cast operator be merged with the prefix unary group, instead of being in a group by itself? I can compile this without error with gcc 4.1.0:
int main()
{
        double foo = 1.0;

        ~(int)foo;

        return 0;
}
If the type cast operator has lower precedence than the bitwise one's complement operator, then the later should be evaluated first, and the compiler would produce the error "wrong type argument to bit-complement."

On the other hand, since these are both prefix operators and right-to-left associative, and if they both have the same precedence level, then the type cast will be evaluated first and there will be no error.

Grokking convoluted expressions

Posted Mar 20, 2007 1:41 UTC (Tue) by ldo (guest, #40946) [Link] (1 responses)

If the type cast operator has lower precedence than the bitwise one's complement operator, then the later should be evaluated first, and the compiler would produce the error "wrong type argument to bit-complement."

Well, actually no, since the syntax of your example is that bitwise-complement is applied to the result of the cast, there's no way not to do the cast first. (The only other way to try to interpret it is that bitwise-complement applies to the type, but C syntax doesn't allow that interpretation.)

You're right that it doesn't have any effect to separate cast out into its own grouping. However, I'm following the groupings in section A7 of K&R2, which puts casting into its own subsection, coming after the other prefix unary operators.

Grokking convoluted expressions

Posted Mar 20, 2007 14:41 UTC (Tue) by tjc (guest, #137) [Link]

Well, actually no, since the syntax of your example is that bitwise-complement is applied to the result of the cast, there's no way not to do the cast first.
Exactly, which is why the type cast operator can't *really* be at a level below the unary prefix operators. If it was, then the one's complement would be evaluated first, which would produce an error since the operand is a floating-point number.
I'm following the groupings in section A7 of K?R2, which puts casting into its own subsection, coming after the other prefix unary operators.
Thanks for the tip, I'll take a look at K?R2 when I get home. There's also a grammar at the back of the book that might reveal why they put the type cast operator in a separate group.

Grokking convoluted expressions

Posted Mar 24, 2007 15:06 UTC (Sat) by muwlgr (guest, #35359) [Link]

By incidence, I used to have a very similar page scotched to the wardrobe near my desk (printed from TurboC 2.0 help system). Very useful during learning C :>

Grokking convoluted expressions

Posted Mar 16, 2007 13:00 UTC (Fri) by pr1268 (guest, #24648) [Link]

That's spooky... But brilliant!

Just curious, are you a philosopher by trade?

Grokking convoluted expressions

Posted Mar 17, 2007 16:04 UTC (Sat) by daniel (guest, #3181) [Link] (1 responses)

It's nice, but is it short enough?

a>b^a>c^c>b

Grokking convoluted expressions

Posted Mar 17, 2007 22:42 UTC (Sat) by ldo (guest, #40946) [Link]

Now that's devious :). Feel free to add it to the page.

Quotes of the week

Posted Mar 15, 2007 15:54 UTC (Thu) by u-ra (guest, #42575) [Link] (15 responses)

Jesus Christ, someone ought to make a t-shirt with this. Brilliant

Quotes of the week

Posted Mar 15, 2007 16:14 UTC (Thu) by tjc (guest, #137) [Link] (14 responses)

Jesus Christ, someone ought to make a t-shirt with this.
Here you go. ;-)

http://www.christianshirts.net/products.php?product=2178

Quotes of the week

Posted Mar 15, 2007 16:33 UTC (Thu) by vmole (guest, #111) [Link] (13 responses)

Spammer. (Apparently, that's too short to pass the LWN comment checker.)

Quotes of the week

Posted Mar 15, 2007 16:54 UTC (Thu) by bronson (subscriber, #4806) [Link] (12 responses)

I think it's just an unfunny joke...
"Jesus Christ, someone ought to make a t-shirt with this." ->
"someone ought to make a t-shirt with Jesus Christ".
Definitely not worth posting though.

Quotes of the week

Posted Mar 15, 2007 16:58 UTC (Thu) by tjc (guest, #137) [Link] (11 responses)

Definitely not worth posting though.
It's OK for someone to post something profane, but it's not OK to respond with gentle humor?

Quotes of the week

Posted Mar 15, 2007 17:03 UTC (Thu) by k8to (guest, #15413) [Link] (7 responses)

I don't think that's universally considered (nor even commonly considered) profane. But that aside, I don't think anyone's complaining that funny is bad, but that they don't think it was funny enough.

Me, I'm doubtful that not-funny-enough is worth posting. But then again, is such an observation worth posting either? Sigh.

Quotes of the week

Posted Mar 15, 2007 19:03 UTC (Thu) by tjc (guest, #137) [Link] (6 responses)

I don't think that's universally considered (nor even commonly considered) profane.
Nothing is universally considered, expect maybe things like "the sky is blue."

As far as commonly considered usage, that depends on where you live. If you live in the southern United States, then it is definitely commonly considered profane to use the phrase "Jesus Christ" in an offhand manner. If you live in Europe, probably not, since only a very small percentage of Europe is Christian.

But then again, is such an observation worth posting either? Sigh.
I'm giving you another chance to resist temptation. ;-)

Quotes of the week

Posted Mar 16, 2007 8:34 UTC (Fri) by u-ra (guest, #42575) [Link] (5 responses)

If you said that seriously, which I doubt, I guess you should check this first: http://en.wikipedia.org/wiki/Religion_in_Europe

Quotes of the week

Posted Mar 16, 2007 14:55 UTC (Fri) by tjc (guest, #137) [Link] (4 responses)

I don't have a clear idea what those numbers mean, since I don't know the questions that were asked on the survey. But it's fairly obvious to even a casual observer that Christianity is not a big part of modern European society.

Quotes of the week

Posted Mar 16, 2007 15:10 UTC (Fri) by k8to (guest, #15413) [Link]

To drag it further off topic, I will give you that modern western europe's society relates to christianity in a notably different way than than some united states towns. I think something along those lines is what you're trying to say.

Quotes of the week

Posted Mar 17, 2007 16:25 UTC (Sat) by hingo (guest, #14792) [Link] (2 responses)

Uh, I'm a European, can I say something?

All European countries are Christian. Northern Europe is Protestant (Lutheran, Anglican), Southern is Catholic and Eastern is (Greek) Orthodox. That being said, most countries today are secular, meaning people are not religious although they do belong to a church and may or may not visit it at Christmas time.

Same goes for my understanding of the word profane. The phrase "Jesus Christ" in the above context is certainly profane purely by definition. Whether a particular reader is aggravated by such profanity is another matter entirely, I certainly am not. As for Europe, at least in Northern Europe a grand mother would likely use that phrase for exclamation. Unless she is religious, in which case she would not dare speak such profanities. See?

Now there... With this post I'm not only off-topic, I'm also teaching Americans English. Where is LWN going...

Quotes of the week

Posted Mar 17, 2007 18:45 UTC (Sat) by tjc (guest, #137) [Link] (1 responses)

All European countries are Christian. Northern Europe is Protestant (Lutheran, Anglican), Southern is Catholic and Eastern is (Greek) Orthodox. That being said, most countries today are secular, meaning people are not religious although they do belong to a church and may or may not visit it at Christmas time.
May or may not visit church at Christmas time? That's an exceedingly broad definition of being a Christian!

That's sort of like saying "I'm a programmer, but I may or may not write a program once a year." :-)

Quotes of the week

Posted Mar 18, 2007 15:44 UTC (Sun) by filipjoelsson (guest, #2622) [Link]

This is so far off topic - that I'm not ashamed of chipping in. ;)

> May or may not visit church at Christmas time? That's an exceedingly broad
> definition of being a Christian!

The keyword was secular. A lot of Europeans belong to churches because it was mandatory to belong to a church up until some 50 years ago in some countries here. Sweden, where I live, is among them. Guess what? We're the most secular country in the world now (or in the top 3 at least) - but still most people belong to a congregation, since their folks did. Up until 7 years ago the church was a part of the state here, the priests where government officials.

Anyway, what does being Christian have to do with the worlds biggest commercial holiday?

Quotes of the week

Posted Mar 15, 2007 18:50 UTC (Thu) by bronson (subscriber, #4806) [Link]

For the record, tjc, I feel it's perfectly OK for you to post that. Since it offered little of value and nothing related to Linux, however, I feel it probably wasn't worth posting here. Subtle but important difference.

Sorry for the noise. I just wanted to make sure that I didn't accidentally join the LWN Posting Police. :)

Quotes of the week

Posted Mar 16, 2007 7:40 UTC (Fri) by u-ra (guest, #42575) [Link] (1 responses)

Wait, wait, wait, what can you possibly be referring to with "profane"?

Quotes of the week

Posted Mar 16, 2007 10:32 UTC (Fri) by nix (subscriber, #2304) [Link]

The T-shirt had some invisible ink on it praising DRM. ;)

Rusty's obfuscated (but serviceable) macro gets an explanation

Posted Mar 15, 2007 16:41 UTC (Thu) by pr1268 (guest, #24648) [Link] (1 responses)

Hehe, reading further down the thread, someone asked for some documentation explaining how this macro works.

Rusty obliged the request with:

+/* GCC is awesome. */
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])      \
  + sizeof(typeof(int[1 - 2*!!__builtin_types_compatible_p(typeof(arr), \
    typeof(&arr[0]))]))*0)

That explains it all so clearly! ;-)

Rusty's obfuscated (but serviceable) macro gets an explanation

Posted Mar 16, 2007 10:32 UTC (Fri) by nix (subscriber, #2304) [Link]

He learned his commenting style from JWZ, I'd say :)

How about this?

Posted Mar 16, 2007 15:24 UTC (Fri) by guobin (subscriber, #12479) [Link]

/* array variable/field/type count */
#define countof(a)        (sizeof(a) / sizeof(((typeof(a)){})[0]))


Copyright © 2007, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds