9void

****** aiju.de_Home_of_aiju ******

****** Notes On Programming In C ******
DISCLAIMER: I don't agree with this anymore but I'm leaving it up for
historical interest.
See also Rob_Pike's_version.
***** Style *****
(Haters gonna hate)
    * Do pick one style and use it consistently.  It's very awkward to read code
      which switches between brace styles all the time.
    * If you work on an existing body of code, use the existing style.  Do not
      introduce another, in particular your own, style.
    * Do not use type prefixes on your names.  Do not use struct prefixes on
      your struct fields.  Examples how not to do it:
      int iFoo;
      char *pcBar;


      struct FooBar {
	  int fb_spam, fb_eggs;
      }
    * Use typedef for your structs:
      typedef struct FooBar FooBar;
      This is preferable to typedef struct { ...  } FooBar; because it makes it
      possible to use FooBar * pointers in FooBar.
    * Do not define cute types.
      typedef int MyVeryOwnInt;
    * Consider the following style for functions:
      int
      foobar(char *foo)
      {
      }
      It allows searching for a function using /^foobar\(/.
    * Do not put braces around single statements, e.g.  don't do
      if(foo){
	  return 0;
      }
    * Use pointers.  Seriously, use pointers.
    * Do not #include .c files.  Just don't.
    * Contrary to popular belief, using goto will not get you killed by a
      raptor.  You should use it sparingly, but it definitely has its
      applications.
    * Do not use const or restrict.  const does not have any effect during
      runtime.  restrict can introduce extra bugs.  Both have no real use.
	  o Many people seem to like const claiming that it "prevents bugs".
	    I'm honestly not sure if I have ever come across a single bug that
	    would have been prevented by const.  Even if there is the odd
	    examples for which it is true, const is a cancer that spreads
	    through entire codebases as the only sane way to use it is to use
	    it consistently (or else you require casts which could mask real
	    bugs).  Considering that it serves little to no purpose it's, in my
	    opinion, just not worth effort.  If you do find yourself stuck with
	    code that insists on it, the magic incantation is #define const.
    * Casts from and to void * are always implicit in C (not in C++).  Explicit
      casts just clutter the code and make you miss out on an opportunity to
      annoy C++ programmers (in a similar vein try using variable names like
      new, class or template).
    * Look at Windows API, glibc header files, Linux kernel source and GNU
      program source as examples how NOT to write code.
    * Learn the operator hierarchy.  Don't put parentheses where they are not
      needed.  This one takes practice.
      if(((((a + b) - c) != d) && (x != (y + z))) || (a > b)) /* is THIS really
      more readable than */
      if(a + b - c != d && x != y + z || a > b) /* this?  */
    * Declare pointers as int *x not int* x because
      int* x, y;
      int *x, y;
      both define x, but not y as a pointer.  The second one makes this more
      obvious.  Also if you do intend two pointers int *x, *y looks better than
      either
      int* x,* y;
      int* x, *y;
***** Avoiding bugs *****
    * Do not define functions like int foobar();.  This is a function with an
      undefined number of arguments, not a function without arguments as you
      might expect.  Write int foobar(void);.
    * Declare all your functions in advance.  Using functions without prototypes
      is a source of bugs.
    * malloc(3) can fail in various ways.  The most straightforward is returning
      NULL, in which case it is a good idea to exit the program.  It can also
      return a seemingly valid address, but your program is killed when you use
      it.
    * Zero all structures (remember that global and static variables are
      automatically zeroed).  Zero all memory allocated with malloc(3).
      (suggestion: create a function emalloc which checks for NULL and zeroes
      memory before returning it.)
    * Check for the following errors and abnormalities, even if they do not
      appear under your configuration:
	  o partial read(2) (not even an error)
	  o partial write(2) (an error, unless a signal interrupted the call)
	  o If your program does signal handling, all blocking syscalls can
	    return prematurely.  Be sure to check and compensate for that.
    * Check for buffer overflows.
    * Always make sure your strings are NUL-terminated.  Beware of functions
      that might not NUL-terminate your strings, e.g.  strncpy(3).
    * Never ever pass user input to printf's first argument or the format
      argument of any other function.
    * Be aware that the fopen(3) family of functions, printf(3) in particular,
      are buffered.
    * Set pointers to NULL after calling free(3) on them (unless of course the
      pointers themselves will be deleted as well).
    * Use volatile for machine registers and variables shared between threads.
    * Watch out for integer overflow.
    * Use the CSP model of threading whenever possible.  Using Go instead might
      be a good idea for thread heavy code.
***** Complexity *****
    * Don't support anything but UTF-8.
    * Do not localize.  English is the STANDARD language.
***** Portability *****
    * Try to avoid using C99 (any newer standard is so full of heresy I refuse
      to consider them C). In particular:
	  o Do not use // comments.
	  o Declare all local variables right at the beginning of a function.
      (Note that Microsoft Visual C does not support these features!) Some
      features, on the other hand, are so widely supported and useful they are
      worth using, e.g.  snprintf.
    * Do not perform arithmetic with void *.  Some compilers don't like that.
      (Cast to char * first)
    * Do not assume that types like int have a particular size.  Use stdint.h's
      int32_t and friends if it matters.
    * Never ever assume a certain endianness.  Very much avoid writing
      endianness dependent code.  Example to read an uint32_t into memory: (it
      is stored in little endian)
      uint32_t i;
      unsigned char buf[4];
      read(fd, buf, 4); /* you should check for errors, EOF etc.  in real code
      */
      i = buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24;
      There are very few instances where the performance benefit of just
      reading into i directly matters (It definitively won't matter if you're
      reading from a hard disk).
    * Never ever assume that a struct has a certain layout in memory.  In
      particular do not use read(2), write(2) or similar functions directly on
      structs.
    * Do not cast pointers to integers.  Just don't.  If you do, make sure it's
      uintptr_t.
    * Avoid using floating point.  It can cause portability trouble.  A lot of
      floating point behaviour is undefined.  If you do use it, you're well
      advised to use double.
    * Do not use non-blocking I/O.  A nice source of portability issues and race
      conditions if you do.
    * Do not use expressions with side-effects in complicated ways.  Do not
      assume that the compiler evaluates things between sequence_points in a
      particular order.
      a[i++] = i; /* undefined behaviour!  */
    * Do not write to string literals:
      char *a;
      a = "hello, world";
      a[0] = 'H'; /* can and will error out */
      There is a trick if you want a modifiable string:
      char a[] = "hello, world";
    * Do not use register.  It most likely does nothing anyway.
    * Never ever use __attribute__ when using gcc.  You're doing it wrong.
***** Performance *****
    * Be aware that string handling in C is unusual.  strlen(2) in particular is
      a O(n) operation.  Use pointers.
***** Preprocessor *****
    * Do not use #define for integer constants.  Use enum:
      enum {
	  FOO = 42,
	  BAR = 23,
      };
    * Avoid using macros.  Really.  If you have macros longer than one line,
      you're probably doing it wrong.
    * Never ever use #if.  You're doing it wrong.
    * Avoid using #ifdef.  It very often is avoidable and only leads to
      convoluted code like this:
      #ifdef WINDOWS
      a = CreateFile(...);
      #endif
      #ifdef LINUX
      a = open(...);
      #endif
      #ifdef MACOSX
      a = open(...);
      #endif
      Better solutions involve concentrating all platform specific code into a
      single file of which you can have multiple versions.  Or in cases like
      this just using the portable (if ugly) fopen(3) family of functions in
      the first place.
      Just look at cpython's source code if you need more examples why not to
      use it.
    * Avoid #include in header files.  This saves you from the usual #ifndef
      DICKS / #define DICKS / ...  / #endif dance.
    * Avoid splitting headers in many small files.  For most projects, I work
      with a file fns.h containing function prototypes and dat.h containing
      everything else.
***** Really Stupid Shit *****
    * Never ever use bitfields (the int a:4; thing; if you never heard of it:
      good for you).  And I mean never ever ever ever ever under no
      circumstances WHATSOEVER.  (They are unportable, ugly and useless; just
      use bit operations).
    * Avoid inline assembly like the plague.  There are very few instances where
      it can be justified.  If you need to use assembly for performance or to
      access machine features, isolate it into a function which can be in a
      separate .asm file You should have and maintain a C version of all "for-
      performance" assembly code.

Powered_by_werc