0

I am newby in programming in C language. Can someone explain me how to "read" declarations like *(float *)a and give some example step by step.

Thanks!

user3840170
  • 26,597
  • 4
  • 30
  • 62
M_sansa
  • 11
  • 2
  • 5
    It's not a declaration. It's dereferencing a variable `a` casted to the pointer to `float`. – Eugene Sh. Aug 30 '16 at 18:28
  • @EugeneSh. please explain more! thanks :) – M_sansa Aug 30 '16 at 18:30
  • Possible duplicate of [What are the differences between a pointer variable and a reference variable in C++?](http://stackoverflow.com/questions/57483/what-are-the-differences-between-a-pointer-variable-and-a-reference-variable-in) – RCB Aug 30 '16 at 18:31
  • Suppose you are writing the `cmp` function required by `qsort` which has two `void*` arguments. *You* know they are actually pointing to `float` so `if( *(float*)a > *(float*)b ) return 1;` is used to cast the correct data type. – Weather Vane Aug 30 '16 at 18:34
  • @RCB - That's about C++. – Oliver Charlesworth Aug 30 '16 at 18:38

2 Answers2

1

*(float *)a is not a declaration; it is a cast expression. In this particular case, it's taking the value of a, treating it as a pointer to float, and dereferencing the result. Most likely a is a pointer to a different type, and we want to treat it as a pointer to float.

As far as pointer declarations are concerned...

A simple pointer declaration looks like

T *p;  // p is a pointer to T

where T is any type (potentially with qualifiers like const or volatile). The type of the object p is "pointer to T"; the type is fully specified by the combination of the type specifiers and qualifiers in T and the declarator *p.

The declarator introduces the name of the thing being declared, along with any type information not provided in the type specifier. In the declaration above *p is the declarator. It provides the name of the object (p) and any additional type information (pointer to). Note that even if you write the declaration as

T* p;

it will be parsed as

T (*p);

The same thing holds for declarations of arrays and functions:

T a[N]; // a is an N-element array of T
T f();  // f is a function returning T

The array-ness of a is given by the declarator a[N] and the function-ness of f is given by the declarator f().

You can combine * with [] and (), like so:

T *a[N];   // a is an N-element of pointers to T
T (*a)[N]; // a is a pointer to an N-element array of T
T *f();    // f is a function returning pointer to T
T (*f)();  // f is a pointer to a function returning T

In both declarations and expressions, the unary * has lower precedence than either postfix [] or (), so *a[N] and *f() are parsed as *(a[N]) and *(f()). If you want a to be a pointer to an array instead of an array of pointers, you must explicitly group the * with a as (*a)[N].

You can further combine these elements like so:

T **p;       // p is a pointer to a pointer to T
T a[N][M];   // a is an NxM array of T
T (*f[N])(); // f is an array of pointers to functions returning T
T (*f())[N]; // f is a function returning a pointer to an array of T
T *(*(*a[N])())(); // a is an array of pointers to functions returning pointers to functions returning pointers to T

Yes, functions can return pointers to arrays and pointers to other functions, and yes, the syntax looks funky, but if follows logically from how declarators work. You just substitute the function call (along with any parameters) for the pointer name:

T (*a)[N] => T (*f())[N], a => f()
T (*f)()  => T (*g())(),  f => g()

Here's an example: the signal function from the C standard library. It's a function that returns a pointer to another function:

void (*signal(int sig, void (*func)(int)))(int);

To read this declaration, start with the leftmost identifier and work your way out, applying the precedence rules given above. Apply those rules recursively to any function parameters:

       signal                                      -- signal
       signal(                          )          -- is a function taking
       signal(    sig                   )          --   parameter sig
       signal(int sig                   )          --   is an int
       signal(int sig,        func      )          --   parameter func
       signal(int sig,      (*func)     )          --   is a pointer
       signal(int sig,      (*func)(   ))          --   to a function taking
       signal(int sig,      (*func)(   ))          --     unnamed parameter
       signal(int sig,      (*func)(int))          --     is an int
       signal(int sig, void (*func)(int))          --   returning void
      *signal(int sig, void (*func)(int))          -- returning a pointer
     (*signal(int sig, void (*func)(int)))(   )    -- to a function taking
     (*signal(int sig, void (*func)(int)))(   )    --   unnamed parameter
     (*signal(int sig, void (*func)(int)))(int)    --   is an int  
void (*signal(int sig, void (*func)(int)))(int);   -- returning void

So, signal is a function that returns a pointer to a function. signal takes two parameters, one a plain int, the other a pointer to a function that takes an int and returns void. Note that in a function declaration, parameter names don't have to be specified. They will need to be specified in the corresponding function definition.

John Bode
  • 119,563
  • 19
  • 122
  • 198
0

In general, you have to care about both the precedence and the associativity of operators: table

In this case, the dereference and the cast operators have the same precedence and are both right-to-left associatives. This means that each operator apply to what is on its right side, and since they have the same precedence, the dereference operator apply after the cast operator, which is on its right side.

So the sequence of operations performed is: access a -> cast it to (float *) -> dereference it.

EDIT: in the case you have an unary operator (dereference, cast, negation, etc.), that operator is always right-to-left associative and it applies after all the expression at its right side as been calculated. So, in our case you can say that the operators are applied from right to left also without looking at the above table.

Davide Visentin
  • 735
  • 5
  • 19