Live data from Hacker News

The "Clockwise/Spiral Rule" in C

c-faq.com

41–49 of 49 posts

Re: The "Clockwise/Spiral Rule" in C

#41
post #3

http://cdecl.org/

there is a cdecl package in all linux distributions, which can be used inside terminal to expand such C declrations. It was really helpful when I started C programming.

Unfortunately the license is not clearly free. This was why we had to drop it from Fedora.

I have tried to contact the original authors, and have got clarifications from all of them except Graham Ross.

So if anyone here knows how to get hold of him, please let me know! (rjones at redhat dot com)

Re: The "Clockwise/Spiral Rule" in C

#42

The "spiral rule" makes for pretty pictures, but unfortunately it isn't correct. One simple example: int *foo[3][4]; The spiral rule would have us read this as "foo is an array [3] of pointers to array [4] of int". What it actually is is "foo is an array [3] of arrays [4] of pointers to int". The correct rule* for parsing declarations is "Start from the thing being declared, and read right until you hit a closing par…

Yes, the Right-Left rule is the one to use; I first read of it in Anderson & Anderson's _Advanced C: Tips & Techniques_. Having that simple rule, there's no need to struggle over qsort()'s declaration and others, or create unnecessary, one-use, typedefs.

Re: The "Clockwise/Spiral Rule" in C

#43
post #32

Earlier quoted context omitted.

The sizeof operator begs to differ.

How does it differ? It just gives the size of the whole object -- that doesn't mean it's not an array of arrays...

To elaborate on what tedunangst said, for those less experienced with C:

To some extent it's a matter of nomenclature, but one can draw a distinction in C between arrays of arrays and 2D arrays. It does matter. The following is an array of arrays of ints (a "ragged array" as tedunangst mentioned), if I malloc an array of pointers to ints and then add a loop that mallocs an array of ints for each a[i]:

  int **a;

  a = malloc(N * sizeof(a[0]));
  int i;
  for(i = 0; i 
Then a[i][j] picks out a single int from the array of arrays. The layout in memory is then like this:

      +--+--+--+-       -+--+
  a:  |  |  |  |   ...   |  |   (array of pointers to arrays of ints)
      +--+--+--+-       -+--+
        |   |
        |   |
        |  +--+--+--+-       -+--+
  a[0]: |->| 1| 2| 3|   ...   |  |  (array of ints)
           +--+--+--+-       -+--+
            |
            |  +--+--+--+-       -+--+
  a[1]:     |->|41|42|43|   ...   |  |  (array of ints)
               +--+--+--+-       -+--+
    .
    .	
    .
Note that you cannot rely on these arrays to have any relationship with each other in respect to their positions in memory. That's entirely up to malloc(3).

However, the following is a 2D array of ints:

  int a[3][4];
The same syntax as before can be used to pick out one of the ints in the 2D array: a[i][j]. But this time the C standard gives us that this object is laid out in memory in row-major order. So if you initialize it like this:

  int a[3][4] = { {1, 2, 3, 4}, { 5, 6, 7, 8 }, { 9, 10, 11, 12 } };
then its memory layout looks like this:

      +--+--+--+--+--+--+--+--+--+--+--+--+
  a:  | 1| 2| 3| 4| 5| 6| 7| 8| 9|10|11|12|
      +--+--+--+--+--+--+--+--+--+--+--+--+
        ^        ^  ^        ^  ^        ^
        |__a[0]__|  |__a[1]__|  |__a[2]__|
This means you can index it manually like this:

  int x = *((int*)a + i * M + j);
where M is the length of each row, in this case M==4. You can't do that with the ragged array-of-arrays.

Exercise: try taking sizeof(a) in both cases, as suggested in the grandparent.

Exercise: 3D arrays?

Re: The "Clockwise/Spiral Rule" in C

#44
"signal"... pfft... entry level kindergarten stuff. Try parsing array of pointers to array of function pointers taking pointer array of arrays with some const and __restrict sprinkled on. And that'd be a warm up. Then name some of the function pointer arguments _const, _restrict and _ - and now we are talking. Spiral out of that!

* This is loosely based on an interview question I got few years ago. I did answer it, then asked similar clusterfuck of a question back. Needless to say it didn't go anywhere.

Re: The "Clockwise/Spiral Rule" in C

#45
post #34

Earlier quoted context omitted.

Just so long as I don't see you filing any bug reports when POSIX changes a header and your code stops compiling. =)

That's why I use *__t (two underscores).

That's not ideal either.

http://www.doc.ic.ac.uk/lab/cplus/c++.rules/chap5.html

"The use of two underscores (`__') in identifiers is reserved for the compiler's internal use according to the ANSI-C standard."

Re: The "Clockwise/Spiral Rule" in C

#46
post #34

Earlier quoted context omitted.

That's why I use *__t (two underscores).

That's not ideal either. http://www.doc.ic.ac.uk/lab/cplus/c++.rules/chap5.html "The use of two underscores (`__') in identifiers is reserved for the compiler's internal use according to the ANSI-C standard."

Are you sure that statement is correct? In my memory, it's only double underscores at the start of identifiers. My final draft of ISO C 11 seems to confirm that:

"7.1.3 Reserved identifiers 1 Each header declares or defines all identifiers listed in its associated subclause, and optionally declares or defines identifiers listed in its associated future library directions subclause and identifiers which are always reserved either for any use or for use as file scope identifiers. — All identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use. — All identifiers that begin with an underscore are always reserved for use as identifiers with file scope in both the ordinary and tag name spaces. — Each macro name in any of the following subclauses (including the future library directions) is reserved for use as specified if any of its associated headers is included; unless explicitly stated otherwise (see 7.1.4). — All identifiers with external linkage in any of the following subclauses (including the future library directions) and errno are always reserved for use as identifiers with external linkage.184) — Each identifier with file scope listed in any of the following subclauses (including the future library directions) is reserved for use as a macro name and as an identifier with file scope in the same name space if any of its associated headers is included. 2 No other identifiers are reserved. If the program declares or defines an identifier in a context in which it is reserved (other than as allowed by 7.1.4), or defines a reserved identifier as a macro name, the behavior is undefined."

Re: The "Clockwise/Spiral Rule" in C

#47
post #34

Earlier quoted context omitted.

That's why I use *__t (two underscores).

That's not ideal either. http://www.doc.ic.ac.uk/lab/cplus/c++.rules/chap5.html "The use of two underscores (`__') in identifiers is reserved for the compiler's internal use according to the ANSI-C standard."

[deleted]

Re: The "Clockwise/Spiral Rule" in C

#48
post #39

This is why I like S-Expressions

S-expressions don't declare types, though. A sexp grammar for the same thing would be basically isomorphic to a fully-parenthesized C type expression. C has some glitches: the fact that the pointer type decoration goes on the left while the array decoration goes on the right is one. The precedence rule that requires parentheses for function pointers is unfortunate. And the putting the decoration on the variable and n…

I think the gist of your argument is this: both C languages and s-expression based languages are touring complete and thus isomorphic.

For any given C compiler I can write a lisp program that gives the same answers for input. Likewise for any Lisp program I can make input for a c compiler that yields the same behavior. I know this because both c and lisp are touring complete. Yay formal languages !!!

But touring completeness and isomorphism are not exactly the same thing. When you run into undefined behavior in your c/c++ program, there does not exist exactly one s-expression to cover the possible interpretations of every compiler. You may need to write several compiler specific s-expressions to cover all the behaviors from the same c expression.

These compiler specific difference break the mappings required for isomorphism.

Lisps also have two different ways of evaluating input. Lazy and strict. So one s-expression may require several c expressions to deal with edge cases. Nothing is perfect.

Sadly, either way you look at it, c expressions are not quite isomorphic to s-expressions.

I agree with you about left to right vs right to left precedence. That's actually why I prefer s-expressions to order of operations and infix notation.

Also some complexity is inherent, some is self imposed. Sometimes static typing is nice and catches errors. Sometimes dynamic typing can save a lot of keystrokes.

Re: The "Clockwise/Spiral Rule" in C

#49
post #46

Earlier quoted context omitted.

That's not ideal either. http://www.doc.ic.ac.uk/lab/cplus/c++.rules/chap5.html "The use of two underscores (`__') in identifiers is reserved for the compiler's internal use according to the ANSI-C standard."

Are you sure that statement is correct? In my memory, it's only double underscores at the start of identifiers. My final draft of ISO C 11 seems to confirm that: "7.1.3 Reserved identifiers 1 Each header declares or defines all identifiers listed in its associated subclause, and optionally declares or defines identifiers listed in its associated future library directions subclause and identifiers which are always res…

You are right, it appears to be C++-specific and looks like a typo in the link.

C++98, 17.4.3.1.2 Global names

- Each name that contains a double underscore (__) [...] is reserved to the implementation for any use.

Post reply on HN