from Hacker News

Strange C Syntax

by Tideflat on 8/2/15, 5:46 PM with 55 comments

  • by cjslep on 8/2/15, 8:47 PM

    These strange syntaxes are perfect additions for the article "How to write unmaintainable code", which already has a Duff's device example:

        switch(count % 8) {
            case 0: do{ putchar('0' + (int)j);
            case 7:     putchar('0' + (int)j);
            case 6:     putchar('0' + (int)j); /* Unrolled
            case 5:     putchar('0' + (int)j);  * for greater
            case 4:     putchar('0' + (int)j);  * speed.
            case 3:     putchar('0' + (int)j);  */
            case 2:     putchar('0' + (int)j);
            case 1:     putchar('0' + (int)j);
        } while(--j > 0);
    
    Without syntax highlighting, a passing glance may not recognize cases 3 through 5 are commented out.
  • by greenyoda on 8/2/15, 6:55 PM

    "You can typedef a function declaration... and declare function prototypes..."

    This is actually a very useful technique that I use all the time. It allows you to make sure that a function and any function pointers that point to it always have matching types (since you only have to change the prototype in one place - the typedef).

  • by m3koval on 8/3/15, 12:20 AM

    The bitfield example is misleading. Section 6.7.2.1/10 of the C99 standard says:

    "The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined"

    There is no guarantee on the order of the bits inside a bitfield. The compiler may also introduce padding, e.g. for alignment purposes. This makes bitfields unusable for unpacking binary data.

    Unfortunately, you're stuck with shifting and masking to replicate the same effect.

  • by saurik on 8/2/15, 10:23 PM

        *(const char * + char *)  The type of int i is converted to 'char *' and multiplied by sizeof(char)
    
    I am pretty certain this explanation does not make any sense: what is really happening here is that the int, for purposes of the addition, is measuring units sizeof the object being pointed to; there is no meaning I know of to adding two pointers.

        /*  This works because "Hello"[5] == 5["Hello"].*/
    
    At this point, you could really just say the following:

        /*  This works because a[b] == *(a + b), and addition is commutative. */
  • by skarap on 8/2/15, 7:59 PM

    This reminded me of another C syntax strangeness: "Flexible array member". It allows you to do something like this:

    struct items_with_header { int header_field1; unsigned int length; double array[]; };

    Then allocate enough memory and use the struct to access it.

    Used it once in a hash-table implementation.

  • by white-flame on 8/3/15, 1:52 AM

    Unions? Function pointers? Typedefs? While it might be bad for karma to point out, intro to C certainly isn't what I expect to be news to "hackers", as per the site's namesake.
  • by HelloNurse on 8/3/15, 8:31 AM

    To consider function types, or unjustified assumptions about bitfield unions, or use of parentheses to control nesting of arrays and pointers in declaration "strange" one must be averse to the C language to the point of intolerance. Backlash from working on a C compiler and wishing the task was easier?
  • by andrewchambers on 8/2/15, 11:57 PM

    I had an "ohh wow" moment when I realized that the keyword typedef is a storage class. This means it can go anywhere static can go. It just means no variable is introduced, only a type name, otherwise it is the same syntax as declarations.
  • by drauh on 8/2/15, 8:40 PM

    Wait till you get a load of the Obfuscated C Contest
  • by thwest on 8/2/15, 7:45 PM

    I was under the impression that C11/C99 only guaranteed that the most recently assigned union member would have an initialized value.
  • by nemesisrobot on 8/3/15, 2:34 AM

    Isn't the first example undefined behavior? I always thought you shouldn't assign data to a union using one member, then access the data using a different member.
  • by halosghost on 8/2/15, 7:45 PM

    > All of these examples you'll see here will compile without warnings or errors even with very strict compiler flags in gcc and clang (gcc -Wall -ansi -pedantic -std=c89 main.c)

    Umm, that's really not that restrictive. Use `clang -Weverything -std=c11 main.c` if you want strict warnings.

  • by fit2rule on 8/2/15, 8:41 PM

    I've found that a great deal of these idioms are explained in the excellent book "Advanced C Programming: Deep C Secrets" by Peter van der Linden. Its one of my goto books for when I want to enhance my 30 years of C-programming experience with a little more insight - I've read it multiple times since it was published, and always learn something new. Check it out if you want to dive more deeply into some of these oddities:

    http://archive.arstechnica.com/etc/books/deep-c.html