Hacker News new | past | comments | ask | show | jobs | submit login

Recently, I learned that instead of saying

    long_struct_name *foo = malloc(sizeof(long_struct_name));
you can say

    long_struct_name *foo = malloc(sizeof(*foo));
since the variable type info is already statically available. That saves some typing, and (more importantly) blocks against bugs from changing one but not the other. I've been meaning to look it up in H&S to make sure it's always safe, but the guy who showed it to me is so strict about safe/standard C that it's likely.

Most of my favorite tricks actually involve the preprocessor, though. I know it's significantly less expressive than the macro systems in Lisp, Scheme, or OCaml, but C would be a very different language without it, and tasteful CPP usage can ease many of C's pain points.

(My other other favorite C programming trick is knowing Lua, which is excellent for scripting C. :) )




It's always safe, and is also the correct way to write the expression.


(My other other favorite C programming trick is knowing Lua, which is excellent for scripting C. :) )

I especially love LuaJIT, whose ffi makes it even easier to interface with C than standard Lua does (and its awesomely fast too). Nevermind that Lua is just nice to work in anyway :)


Where would one start learning to script C with Lua?


The best book for Lua by a longshot is Roberto Ierusalimschy's _Programming in Lua_, second ed. (http://www.inf.puc-rio.br/~roberto/pil2/) It covers the core language and the C API with the same clear, erudite treatment as K&R. (He is one of the core Lua authors.)

Once you get the big ideas, there's a very detailed reference online (http://www.lua.org/manual/5.1/), and the mailing list and wiki at http://lua-users.org/ also have a lot of helpful info.

Lua is transitioning from 5.1 to 5.2 right now, which introduces some changes (improvements to the GC, adding to the standard libraries, and improving the package/module system). The main language and C API haven't changed significantly from 5.1; you should be fine if you learn 5.1 now and update later. Lua is small enough that you could add 5.1 to your projects as a library dependency and maintain it yourself, though - it's only about 16,000 lines of code.


Variables are in scope in their own initializers. This is fun when you inadvertently write something like:

    int length = ...;
    ...more code, lose your concentration...
    if(x) {
        int length = length / 2 + 1;
        ...
    }
This neither produces an error nor does what you'd expect, but just ends up being a creative way to initialize the inner length variable with garbage. I've done this more than I care to admit.


If you're using gcc, you can compile with "-Wshadow" to get a warning for this type of problem.

See: http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html


Definitely. Know your warning options! Also, try using multiple compilers. tcc compiles very quickly, clang often has better error messages, etc.

Speaking of variable shadowing: It's usually worth wrapping any preprocessor macros in a "do { ... } while (0)" block unless you deliberately want variable definitions to escape (in which case, token pasting a suffix is usually a good idea).


Isn't "do { ... } while (0)" the same as just "{ ... }"?

I sometimes use "{ ... }" to limit the scope of a variable that is only needed for a small section of code.


Former lets break'ing out, latter doesn't.


do { ... } while (0) makes your macro behave like a statement (i.e. the semicolon is mandatory)


Yes. I don't include the trailing semicolon in macro definitions, because I expect the macro to be followed by them:

    MACRO(foo);


({ ... }) does this too. (Is this GCC-specific?)


That is a gcc extension. The construct as a whole has the value of the last statement executed within. Usually an inline function is preferable since it achieves the same thing using only standard syntax.


Would be nice if there was one which would warn for this specific case but not shadowing in general, which I occasionally like. (This probably makes me a bad person.)


It certainly doesn't make you a bad person. If lexical scoping wasn't the intent of the language authors, it wouldn't exist. I tend to agree that the warning is more of a hassle than it's worth. Though I guess it can be argued that if your scoping is so deep that you actually need to reuse names, that perhaps some refactoring should be in order.


Seeing a variable shadow something in an outer scope makes me cringe, simply because the decrease in readability far outweighs any benefit it could give. You might remember how things are, but the poor sap who has to keep extra scoping depths in his mind just to maintain your code will curse your name every day.


Also, sizeof is an operator, not a function, so you can write that as

    long_struct_name *foo = malloc(sizeof *foo);


This is true but there is a qualifier here:

If a type name is used, it always needs to be enclosed in parentheses, whereas variable names and expressions can be specified with or without parentheses.

So

    long_struct_name *foo = malloc(sizeof long_struct_name)
won't compile.


To avoid the duplication, with risk of mismatch, and to make it one less thing for the reader to check, I have

    #define NEW(a) ((a) = emalloc(sizeof(*(a)))) 
    NEW(foo);
Similarly with NEW0() and ecalloc(). Yes, the macro uses the parameter more than once, and yes it's another macro for the reader to grasp, but it's a simple one and NEW() is used so widely it's soon learnt.


Indeed this is good style. The following, however, is not good style for allocating an array:

    long_struct_name *fooArray = malloc(count * sizeof * fooArray);




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: