back
64 comments
This is fair. In C, you can't ever let yourself forget whether you have a pointer or an integer or a signed value or an unsigned value. The compiler will not protect you from mistakes, and in the kernel, mistakes are called "remote root exploits". (Remember the bug where someone was derefrencing a null pointer, except that 0 is a valid memory address in kernel land? Yeah.)

But don't do this in high-level code. There, you should use types that are as descriptive as possible, as that will greatly improve readability and maintainability.

In C, you can't ever let yourself forget whether you have a pointer or an integer

A C compiler will generally keep you from forgetting that just fine.

What I meant to say is that it won't prevent you from writing something like:

   p = q + offset
When you really meant:

  *p = *q + offset
Hence, careful understanding of the type of p and q are important, so you can decide what you really mean.
No this is very, very wrong.

Consider:

  unsigned long addr_t = &x;
This is not only completely legal ANSI C but is also idiomatic in kernel development.
'generally'. It's the idea that you can easily mix up pointers and integers in C (and need to carefully remember types, etc) without getting told off by the compiler that's 'very, very wrong'. In your case, gcc will happily tell you:

warning: initialization makes integer from pointer without a cast

Without explicit casts, the compiler won't let you confuse pointers with integers without a warning or an error.

Sorry, what?

    $ cat test.c
    int x;
    unsigned long addr_t = &x;

    $ cc  test.c
    test.c:2: warning: initialization makes integer from pointer without a cast
...especially if you use proper CFLAGS (-Wall -Werror at least, -Wextra if you want to hang with the cool kids).
Yes, -Wall -Werror are mandatory for kernel development.
That's wacky. When I was first getting into OSS, one of the most confusing things about code was typedefs. I knew the basics of C, and looking back on it a lot of what confused me was actually pretty straightforward code that I probably would have been able to piece together, but the use of arbitrary type names (which I didn't even know was possible) stopped me from even trying on more than one occasion.

That's a point in favor of Ruby's "the most readable solution is the most elegant" philosophy over, say, Perl's inverse: It's cool to feel like a member of the club, but if writing that extra line means a beginner (or even a child) can more easily figure out what it does, and she gets interested in programming because of it, that's a lot better for the hacking community as a whole.

You're misinformed about Perl's philosophy. "There is more than one way to do it" doesn't mean they're all good, and all well respected by the community. There is always more than one way to do it and I have yet to see a single production-grade programming language where that isn't the case. If it were as you said, there wouldn't be a Modern Perl movement, there wouldn't be tons of syntax extensions, and extensions to the core to allow better and more powerful syntax extensions.
I didn't intend any slight against Perl (nor an endorsement of Ruby, for that matter), and I know I shouldn't speak on a language I don't know so well. I've always understood the general trend in Perl to be towards economy rather than expressiveness, but I'm totally willing to admit that may no longer be the case.
I'm sorry if I misinterpreted your statement. I just wanted to clarify that "the most unreadable solution is the most elegant" is not Perl's philosophy by far :) More the opposite.

Most of the times you see Perl hackers celebrate some kind of complex syntax expression, it's mostly not the syntax they're enjoying, but the expressed principle. You could still hide it behind a DSL, which most of the time makes sense anyway in production code; DRY and all that. But that would also hide the principles and implementation that was used. So, in generally the Perl community will communicate ideas and concepts via short Perl snippets, and Perl's freedom of syntax makes that easily possible even on Twitter or IRC.

In Perl, expressiveness was always very important. It was just done by the use of symbols and syntax instead of words. It's always a trade-off between being able to read an algorithm without knowing the language, and being able to express your ideas concisely. Personally, I have more troubles with sigil-less variables than with any implementation that uses any kind of symbol to identify them. Others find them distracting. It's a personal choice.

If you have complex nested expressions in Python that do lots of things, you should put it in a function and call it by name. It's the same thing in Perl.

I think OpenBSD has a similar culture:

http://marc.info/?l=openbsd-cvs&m=117270339530912

For those who don't click the link... it's from Theo:

Log message: the_t world_t would_t be_t a_t better_t place_t if_t some_t people_t did_t not_t feel_t the_t need_t to_t typedef_t everything_t

So, instead of fixing the language, you fix yourself. Linus was right when he basically said that whenever you are dealing with a broken language, you have to develop broken habits too.

    > And never _ever_ make the "pointerness" part of the type. People who 
    > write 
    >         typedef struct urb_struct * urbp_t; 
    > (or whatever the name was) should just be shot. I was _soo_ happy to see 
    > that crap get excised from the kernel USB drivers.
Amen. And people who use ampersand pass-by-reference in C++ ( foo(int &i) ).
> And people who use ampersand pass-by-reference in C++ ( foo(int &i) ).

Why?

I don't know what the OP's beef is. There's nothing semantically wrong or confusing about this.

However, for simple types like int and float, there's no performance advantage to passing the value as a reference. It generally takes as long to construct the temporary reference as it does to copy the value.

For more complex types like structures or objects, then yeah, you're better off passing by reference.

Yeah, I didn't mean "int" to be the offensive part.

Read my response. I'm not talking about performance, you shouldn't be copying around large structs or strings no matter what, I'm talking about code readability.

In general, your compiler will optimize the crap out of primitive type copies (and most struct copies too, these days) anyway, so it's less of a performance argument as it used to be.

Because it gives you no more power than passing a pointer. If you're handling pointers, it's better to be totally explicit about what you're doing.

I don't want to read your function call that looks like it passes a whole object and have to check the function header to see that it's actually a reference getting passed, I'd rather see the address taking right at the function call.

A decent point. Google uses the pointer-ness or const-reference-ness of a parameter to signal what the parameter is going to be used for [1]. But at the end of the day reference modification is the kind of basic language feature that you should expect to see people using.

[1] http://google-styleguide.googlecode.com/svn/trunk/cppguide.x...

This actually bothered me to no end at google. At the API level, it's great, I can learn a lot about what your function is going to do just by looking at the signature, but when reading code that uses an API I don't know, it's hell. For me, the extra help you get by looking at a function signature really isn't that great, when I should have the same information available in the documentation that had damn well better accompany the function signature in your header.
I completely agree with you. Worse, if at some point you actually need a pointer of the object to do arithmetic you end up grabbing a pointer of the reference which just puts everything to hell.
I liked this this reply farther in to the thread: "inlines, when used properly, are _not_ larger than not inlining"

http://lkml.indiana.edu/hypermail/linux/kernel/0206.1/0843.h...

My usual rule is to not inline anything that calls a full fledged function, and to only explicitly inline things that are truly on high performance paths. Basically, trust that the compiler will inline or not inline the rest as appropriate. But this is another interesting metric to consider.

My usual rule is to not inline anything that calls a full fledged function, and to only explicitly inline things that are truly on high performance paths. Basically, trust that the compiler will inline or not inline the rest as appropriate. But this is another interesting metric to consider.

That's pretty much correct. Keep in mind, though, that inline has different consequences in a header file. There are good and bad reasons for that kind of usage.

"... and then use "counter_t" all over the place. I think that's not just ugly, but stupid and counter-productive. It makes it much harder to do things like "printk()" portably, for example ("should I use %u, %l or just %d?") ..."

Just do this: printk("count: " COUNTER_T_FORMAT_SPECIFIER "things", c);

So instead of

printk("subtotals: a %d, b %d, c %d, total %d\n", a,b,c,a+b+c);

you have

printk("subtotals: a " COUNTER_T_FORMAT_SPECIFIER ", b " COUNTER_T_FORMAT_SPECIFIER ", c " COUNTER_T_FORMAT_SPECIFIER ", total " COUNTER_T_FORMAT_SPECIFIER "\n", a,b,c,a+b+c);

and soon you (1) can't read your code at all because 60% of it is shouty stuff in your calls to printk and (2) even the printk calls are awkward to read because your eyes have to skip over all the shouty stuff to work out what the output's actually going to look like.

(Perhaps that was your point, in which case I apologize for thinking it needed spelling out more explicitly.)

I was trying to be sarcastic.
If you're going to be sarcastic, be so heavy-handed about it that you could sell it as a Methodology later. :) Otherwise, some people will take it at face value.
Please don't. I once dealt with code like this and it becomes unreadable very quickly, especially if many different types are involved.

However, if printk would be declared with __attribute__((format(printf, 1, 2)) (I don't know if it is), gcc would warn if the format string contains specifiers which do not match the given types, regardless of any typedefs.

Just imagine having Linus as your teacher in a "Programming C" class...
oh, to be so lucky...
Don't be so sure that all of Linus' opinions are valid for all areas of programming, or even in all situations within the kernel.
They aren't, but it would be nice to see all his opinions laid out at once so I could absorb the good ones.
Mostly agree with Linus that typedef abuse is annoying except one example: size_t is platform-dependent and not the same as unsigned int.
I also do not understand his

"We actually have real _problems_ due to this in the kernel, where people use "off_t", and it's not easily printk'able across different architectures (we used to have this same problem with size_t)."

I see the problem with printk, but giving up the ability to typedef architecture-dependent types such as size_t because of it? The proper reaction, IMO, would have been to fix printk. Given that gcc already checks compatibility between format strings and arguments, it should not be that hard to add a special format character (say %?), and have the compiler replace it by a correct character for the argument passed.

I agree except for the part about typedef'ing pointers. If you never typecast a pointer, then you can't ever have compile time and run time encapsulation (better than C++ gives with "private"!) through opaque pointers...
Why not? Just don't ship the definition of your struct in your headers, only declare them.
The API is more confusing if they always have to lug around the extra * and type out struct if they can never dereference it. I am strongly in favor of typedefing pointer types that are strictly private.
regards something specific Linus said:

"We should also have some format for printing out "u32/u64" etc, but that's another issue and has the problem that gcc won't understand them, so adding new formats is _hard_ from a maintenance standpoint. "

do they not use inttypes.h for that?

http://linux.die.net/man/3/priu32

I understood that to refer to printf-style format specifiers that printk() uses. GCC can do type-checking for those: http://www.ohse.de/uwe/articles/gcc-attributes.html#func-for... -- but not if you invent your own % codes.
Linux is the implementation; if anything, it should provide a inttypes.h.
Well, no. inttypes.h is defined in the ANSI specification and is provided by glibc. If it were unistd.h you would be right.
I doubt the kernel can use anything that is defined in the glibc...
I primarily use them with c++ containers as doing so allows you to switch from a vector to a map without changing a lot of other things.
Odd to be reminded of Transmeta and Linus working there.. that's 8 years ago already?