1. 33
  1.  

  2. [Comment removed by author]

    1. 2

      It should be “Use goto well (best general purpose option)” :)

      I still prefer a wrapping function so instead of goto or even while/break, we can just do return and the wrapping function does all clean up. I readily admit however that this is the cleanest option in all cases, it bloats the code and wouldn’t really be worth it for functions that are less than 8 lines say. Also if you have say 5 allocations in the wrapping function then it can potentially obfuscate what is happen as the alloc/dealloc and use are now split up, which may be harder to refactor because you have to realise that the wrapping and child function rely on each other.

    2. 3

      Highlights for me:
      Write sample code using your API before you define it (I do comments for the tasks my application needs to complete, then fill out the function calls/variables I need to make that happen, then go to the library side and implement whatever the application tries to call)
      Public APIs should have some sort of prefix or namespace
      Aside: any language that uses keywords like public and private to determine visibility instead of placement/scoping is bad (Well yes, but it is what we have, I’d argue that any language that doesn’t have constructors and destructors is bad :) )
      You should pretty much always use -> instead of .
      I think this is the most important trick for making C code beautiful (I prefer references with . but I do use C++ not C, I guess if a language picked just one for both uses like Java does it would be cleaner. If -> was the only way for both pointers and references then I would probably like -> more :) )
      The inline keyword should be used rarely if ever, Compilers basically ignore it, for good reason (Good advice)
      Don’t deal with buffers one byte at a time (Yeah, I hadn’t really explicitly thought about that, but it is a good idea, I’m itching to look over all my code now and see if I ever have a function that just processes a single byte/pixel)
      And anyone that reads MollyRocket/Jeff and Casey obviously knows what they are talking about.

      1. 3

        Assert that buffers are entirely zeroed before freeing

        Is this really what should be done? calling memset before free? I guess it is being defensive, but it seems to be an expensive operation.

        1. 1

          I read this in the sense of ASSERT(), not ensure.

        2. 2

          Use struct x asdf[1] to get pointers with inline storage

          Would somebody mind expanding on this?

          1. 7

            It allocates a struct x on the stack and gives you a pointer to it. It’s equivalent to:

                struct x fdsa;
                struct x * asdf = &fdsa;
            
            1. 4

              That’s…weird. I haven’t run into that idiom yet. Could you provide a large sample to help eradicate my ignorance?

              1. 6

                It looks like the author prefers to keep all structure references as pointers, instead of some being pointers and others being values. So instead of:

                struct timeval tv;
                struct timezone tz;
                gettimeofday(&tv, &tz);
                do_something(&tz);
                do_something_else(tz.tz_minuteswest);
                

                The author would prefer,

                struct timeval tv[1];
                struct timezone tz[1];
                gettimeofday(tv, tz);
                do_something(tz);
                do_something_else(tz->tz_minuteswest);
                

                I don’t have a real preference between these styles when taken on their own. One advantage of the 2nd one is that code in functions that take structs as parameters, and code in functions that allocate the storage themselves, is written in the same way.

                1. 1

                  So, there’s a style question.

                  I generally prefer to typedef my struct types, and then I don’t have to explicitly struct everywhere in functions and whatnot…why don’t people do that more?

                  1. 4

                    I really hate typedeffing structs and unions because it hides information. Information which understood wrongly causes big chunk of bugs in C programs.

                    • Especially it hides information about size, which obscures how things should be allocated, freed and handled. If I know that codebase uses typedeffing for structs and I see stack allocated FancyType tmp I have think about ALL possible things that could go wrong with allocating and passing reference to that variable (oh wow, there is lot of those). In case of basic types, world is so much simpler.
                    • Unions are pretty scary things in sense of how easily things can go wrong. Hiding that danger is evil
                    • Thinking about struct alignments becomes harder: is this field enum, struct or union? Is there padding? In environments where you actually need C, you really need to care about this.

                    In short, I want see at glance as many potential pitfalls as possible and typedeffing works against that.

                    1. 2

                      I think it depends on your codebase. In SmartOS and illumos, folks are definitely strongly encouraged (through review, etc) to use the style:

                      typedef struct new_type {
                              int nt_num;
                              char nt_path[MAXPATHLEN];
                              boolean_t nt_yesno;
                      } new_type_t;
                      

                      Our struct proc is better spelt proc_t, etc. Note, also, the struct members are prefixed with a common and relatively unique string to make searching and reading the code easier.

                      1. 3

                        Depending on where this is used, you have to keep in mind that _t is part of the reserved namespace in POSIX.

                        1. 1

                          That’s pretty much exactly what I’ve done in my codebases, given the opportunity. I was just curious why people do it any other way.

                  2. 2

                    Well, it gives you an array object that will (often, but not always) decay to a pointer, not an actual pointer, so no, not actually equivalent. Beware of surprises when applying sizeof