Pages

Tuesday, October 25, 2011

Demystifying complex C declarations.

I have seen many times people complaining of interviewer giving them shit looking declaration and ask us to tell them what it is..
Ex. :
int * p :
pointer to an integer :
[:D]..
okay.. how about this..

 void (*signal(int, void (*fp)(int)))(int); 


To some even this may look easy but to me I put down my pencil and got back to facebook to relieve from tension.
Following is the illustration of one simple method I stumbled across and felt it worked for any kind of declaration.

If there is/are any exception(s) to the following, please feel free to discuss.


[This was posted to comp.lang.c by its author, David Anderson, on 1994-05-06.].. and I read on c-facts ;)

The ``Clockwise/Spiral Rule''

By David Anderson

There is a technique known as the ``Clockwise/Spiral Rule'' which enables any C programmer to parse in their head any C declaration! There are three simple steps to follow:
  1. Starting with the unknown element, move in a spiral/clockwise direction; when ecountering the following elements replace them with the corresponding english statements:
    [X] or []
    => Array X size of... or Array undefined size of...
    (type1, type2)
    => function passing type1 and type2 returning...
    *
    => pointer(s) to...
  2. Keep doing this in a spiral/clockwise direction until all tokens have been covered.
  3. Always resolve anything in parenthesis first!

Example #1: Simple declaration

                     +-------+
                     | +-+   |
                     | ^ |   |
                char *str[10];
                 ^   ^   |   |
                 |   +---+   |
                 +-----------+
Question we ask ourselves: What is str?
``str is an...
  • We move in a spiral clockwise direction starting with `str' and the first character we see is a `[' so, that means we have an array, so...
    ``str is an array 10 of...
  • Continue in a spiral clockwise direction, and the next thing we encounter is the `*' so, that means we have pointers, so...
    ``str is an array 10 of pointers to...
  • Continue in a spiral direction and we see the end of the line (the `;'), so keep going and we get to the type `char', so...
    ``str is an array 10 of pointers to char''
  • We have now ``visited'' every token; therefore we are done!

Example #2: Pointer to Function declaration

                     +--------------------+
                     | +---+              |
                     | |+-+|              |
                     | |^ ||              |
                char *(*fp)( int, float *);
                 ^   ^ ^  ||              |
                 |   | +--+|              |
                 |   +-----+              |
                 +------------------------+
Question we ask ourselves: What is fp?
``fp is a...
  • Moving in a spiral clockwise direction, the first thing we see is a `)'; therefore, fp is inside parenthesis, so we continue the spiral inside the parenthesis and the next character seen is the `*', so...
    ``fp is a pointer to...
  • We are now out of the parenthesis and continuing in a spiral clockwise direction, we see the `('; therefore, we have a function, so...
    ``fp is a pointer to a function passing an int and a pointer to float returning...
  • Continuing in a spiral fashion, we then see the `*' character, so...
    ``fp is a pointer to a function passing an int and a pointer to float returning a pointer to...
  • Continuing in a spiral fashion we see the `;', but we haven't visited all tokens, so we continue and finally get to the type `char', so...
    ``fp is a pointer to a function passing an int and a pointer to float returning a pointer to a char''

Example #3: The ``Ultimate''

                      +-----------------------------+
                      |                  +---+      |
                      |  +---+           |+-+|      |
                      |  ^   |           |^ ||      |
                void (*signal(int, void (*fp)(int)))(int);
                 ^    ^      |      ^    ^  ||      |
                 |    +------+      |    +--+|      |
                 |                  +--------+      |
                 +----------------------------------+
Question we ask ourselves: What is `signal'? Notice that signal is inside parenthesis, so we must resolve this first!
  • Moving in a clockwise direction we see `(' so we have...
    ``signal is a function passing an int and a...
  • Hmmm, we can use this same rule on `fp', so... What is fp? fp is also inside parenthesis so continuing we see an `*', so...
    fp is a pointer to...
  • Continue in a spiral clockwise direction and we get to `(', so...
    ``fp is a pointer to a function passing int returning...''
  • Now we continue out of the function parenthesis and we see void, so...
    ``fp is a pointer to a function passing int returning nothing (void)''
  • We have finished with fp so let's catch up with `signal', we now have...
    ``signal is a function passing an int and a pointer to a function passing an int returning nothing (void) returning...
  • We are still inside parenthesis so the next character seen is a `*', so...
    ``signal is a function passing an int and a pointer to a function passing an int returning nothing (void) returning a pointer to...
  • We have now resolved the items within parenthesis, so continuing clockwise, we then see another `(', so...
    ``signal is a function passing an int and a pointer to a function passing an int returning nothing (void) returning a pointer to a function passing an int returning...
  • Finally we continue and the only thing left is the word `void', so the final complete definition for signal is:
    ``signal is a function passing an int and a pointer to a function passing an int returning nothing (void) returning a pointer to a function passing an int returning nothing (void)''
The same rule is applied for const and volatile. For Example:
 const char *chptr;
  • Now, what is chptr??
    ``chptr is a pointer to a char constant''
How about this one:
 char * const chptr;
  • Now, what is chptr??
    ``chptr is a constant pointer to char''
Finally:
 volatile char * const chptr;
  • Now, what is chptr??
    ``chptr is a constant pointer to a char volatile.''
Practice this rule with the examples found in K&R II on page 122.
Copyright © 1993,1994 David AndersonThis article may be freely distributed as long as the author's name and this notice are retained.


Friday, October 21, 2011

Open Question : Reason for restriction in conversion of pointers to reference of pointer to const

OS : Win XP
Env: VC++ 2008


void foo_ptr(const char * & ptr) //reference to a pointer to a constant character
{
return;
}


//allowed
void foo_char(const char & p_Char) //reference to a constant character
{
return;
}
int main()
{
char ch = 'd';
char *ptr =  "anuh";

foo_char(ch);


! //foo_ptr(ptr); //NOT ALLOWED syntax error, vc++, 2008
return 0;
}

I am interested in knowing the reason of syntax error when we call foo_ptr. When foo_char is allowed why not foo_ptr.

just to keep updated the same question has been asked http://stackoverflow.com/questions/7850843/c-need-reason-for-error-cannot-convert-parameter-1-from-char-to-const


Thursday, October 6, 2011

Why size(Structure) differ from sum of actual sizes of individual members

Same Data Members : Different Sizes

struct  MyStructA {
   char a;
   char b;
   int  c;
};

struct MyStructB {
   char a;
   int c;
   char b;
};

int main(void) {
        int sizeA = sizeof(struct MyStructA);
        int sizeB = sizeof(struct MyStructB);

        printf("A = %d\n", sizeA);//->8
        printf("B = %d\n", sizeB);//->12 in arch x86, DevCPP Compiler
        getch();
        return 0;
}
(via : forum)


(from Wiki)

struct student{
  char grade; /* char is 1 byte long */
  int age; /* int is 4 bytes long */
};
 
printf("%zu", sizeof (struct student));
The reason for this is that most compilers, by default, align complex data-structures to a word alignment boundary. In addition, the individual members are also aligned to their respective alignment boundaries. By this logic, the structure student gets aligned on a word boundary and the variable age within the structure is aligned with the next word address. This is accomplished by way of the compiler inserting "padding" space between two members or to the end of the structure to satisfy alignment requirements. This padding is inserted to align age with a word boundary. (Most processors can fetch an aligned word faster than they can fetch a word value that straddles multiple words in memory, and some don't support the operation at all[3]).

This also has roots into the bus size, (which is word size), making the size of structure integral multiple of bus size helps processor fetching the data faster.
How ?? : > i  l update as soon as i get crude answer.

Wednesday, October 5, 2011

C/C++ : free or delete will NOT release memory back to OS

following is what i found really useful for knowledge sake and would also help in case we are planning to build large systems using C/C++. I have read about this on post by Murali MALLINA, Sr. Soft E in Alcatel Lucent on one of the internal forums.

he said as 

When you call free() or delete(), it will NOT really release any memory back to OS. Instead, that memory is kept with the same process until it is terminated. However, this memory can be reused for any future allocations by the same process. This freed memory is never released to OS, even when the system is out of memory and other processes need memory. That means, a process is stuck with the largest level of memory allocation throughout its life time.

This is big concern for most processes that are expected to run (literally) forever without a restart.

There is an alternative, by linking to mapmalloc library, that uses map/unmap instead of sbrk for memory allocation. When linked with this library, memory could be really released to operating system when free/delete is called. However, memory allocation could be potentially 5 times slower. One heck of a trade off!


Hope this information will help in your designs.  

:-o :-o