Complex declarations
Here is a great article about how to read complex declarations in C: http://www.codeproject.com/KB/cpp/complex_declarations.aspx
It helped me a lot!
Especially - You should read "The right rule" section. Here quote:
int * (* (*fp1) (int) ) [10];
This can be interpreted as follows:
- Start from the variable name -------------------------- fp1
- Nothing to right but ) so go left to find * -------------- is a pointer
- Jump out of parentheses and encounter (int) --------- to a
function that takes an int as argument- Go left, find * ---------------------------------------- and returns a pointer
- Jump put of parentheses, go right and hit [10] -------- to an array of
10- Go left find * ----------------------------------------- pointers to
- Go left again, find int -------------------------------- ints.
Complex C declaration
I haven't done this in a while!
Start with foo
and go right.
float * (*(*
foo()
)[SIZE][SIZE])()
foo is a function with no arguments...
Can't go right since there's a closing parenthesis. Go left:
float * (*(
* foo()
)[SIZE][SIZE])()
foo is a function with no arguments returning a pointer
Can't go left further, so let's cross the parentheses and go right again
float * (*
(* foo())
[SIZE][SIZE])()
float * (*
(* foo())[SIZE]
[SIZE])()
float * (*
(* foo())[SIZE][SIZE]
)()
foo is a function with no arguments returning a pointer to an array of SIZE arrays of SIZE ...
Closing parenthesis reached, left again to reach a pointer symbol:
float * (
*(* foo())[SIZE][SIZE]
)()
foo is a function with no arguments returning a pointer to an array of SIZE arrays of SIZE pointers to ...
Left parenthesis again, so we cross it and go right again:
float *
( *(* foo())[SIZE][SIZE])
()
float *
( *(* foo())[SIZE][SIZE])()
foo is a function with no arguments returning a pointer to an array of SIZE arrays of SIZE pointers to a function with no arguments...
And left to the end
float * ( *(* foo())[SIZE][SIZE])()
foo is a function with no arguments returning a pointer to an array of SIZE arrays of SIZE pointers to a function with no arguments returning a pointer to float
And whoever wrote that, please teach him to use typedef
:
// Function that returns a pointer to float
typedef float* PFloatFunc ();
// Array of pointers to PFloatFunc functions
typedef PFloatFunc* PFloatFuncArray2D[SIZE][SIZE];
// Function that returns a pointer to a PFloatFuncArray2D
PFloatFuncArray2D* foo();
How to decipher complex pointer declarations in C?
cdecl.org is often linked to such questions. No doubt that it make easier to decipher any complex declaration, but at the same time it just provide an abstracted information. Being a C or C++ programmer one should know how to decipher complex declaration manually. Spiral Rule help to some extent but fails in some cases. This answer will help programmers to decipher any complex declaration manually.
Remember these two simple rules:
- Always read declaration from the inside out.
- When there is a choice, always favor
[]
and()
over*
.
The first rule simply states that, locate the variable that is being declared and start deciphering the declaration from it.
For second rule, if *
precedes the identifier and []
or ()
follows it, then the identifier represents an array or function (respectively), not a pointer.
Example 1:
char *y[5];
- Variable/identifier is
y
. *
precedesy
and follows[]
.y
must be an array.
Combining above deciphering will result in: y
is an array of 5
pointers to char
.
Also note that you can always use parentheses to override the normal priority of []
or ()
.
Example 2:
void (*pf) (int);
- Variable/identifier is
pf
. *pf
is enclosed in parenthesis, it must be a pointer.()
follows*pf
, meanspf
must points to a function.- Since
()
enclosesint
, function must expects an argument of typeint
.
So, pf
is a pointer to function that expects an int
argument and returns nothing.
Now, what would you get after deciphering the following declaration
int *(*a[5])(void);
?
Answer:
a
is an array of pointers to functions that expects no argument and returning pointer toint
.
Note:
Note that both of
char *y[];
char **z[];
will cause compilation error if they are not declared as arguments of a function. If they are function's argument then char *y[]
is equivalent to char **y
and char **z[]
is equivalent to char ***z
.
If that's not the case, then you need to specify the dimension as I did in my first example.
Complex pointer declarations
This declaration indeed should not be allowed; functions may not return array types, and you may not have arrays of function type:
6.7.6.2 Array declarators
Constraints
1 In addition to optional type qualifiers and the keywordstatic
, the[
and]
may delimit
an expression or*
. If they delimit an expression (which specifies the size of an array), the
expression shall have an integer type. If the expression is a constant expression, it shall
have a value greater than zero. The element type shall not be an incomplete or function
type. The optional type qualifiers and the keywordstatic
shall appear only in a
declaration of a function parameter with an array type, and then only in the outermost
array type derivation.
...
6.7.6.3 Function declarators (including prototypes)
Constraints
1 A function declarator shall not specify a return type that is a function type or an array
type.
C 2011 Online Draft
Emphasis added. I don't know why cdecl doesn't return some kind of error on that.
If you want a function that returns a pointer to an array, you'd write
int (*p())[N];
This parses as
p -- p is a
p() -- function returning
*p() -- pointer to
(*p())[N] -- array of
int (*p())[N]; -- int
If you want an array of function pointers, you'd write
int (*p[N])();
which parses as
p -- p is an
p[N] -- array of
*p[N] -- pointer to
(*p[N])() -- function returning
int (*p[N])(); -- int
If you want a function that returns a pointer to an array of pointers, you'd write
int *(*p())[N];
which reads as
p -- p is a
p() -- function returning
*p() -- pointer to
(*p())[N] -- array of
*(*p())[N] -- pointer to
int *(*p())[N]; -- int
Postfix []
and ()
have higher precedence than unary *
, so:
T *a[N]; // a is an array of pointer to T
T (*a)[N]; // a is a pointer to an array of T
T *f(); // f is a function returning pointer to T
T (*f)(); // f is a pointer to a function returning T
Starting with those rules, you can use substitution to build more complex declarations. If you want a function returning a pointer to an array, take
T (*a)[N];
and replace a
with a function declarator:
T (* a )[N];
|
V
T (* f() )[N];
If you want an array of pointers to functions, take a function pointer declarator
T (*f)();
and replace f
with an array declarator:
T (* f )()
|
V
T (* a[N] )();
From here, you should be able to read (and generate) more complex types.
cdecl's a nice tool, but once you learn how C declaration syntax really works, you shouldn't need it anymore.
Complex declaration in C- Programming language
Simply break the declaration into parts.
The inner most pair of braces : ( * f[3] ) means 'f' is an array of 3 elements which are pointers.
( *f )()
means 'f' is a pointer to function, so( * f[3] ) ()
means f is an array of 3 pointers to function.
( * ( * f[3] ) ())
means f is an array of 3 pointers to function returning a pointer.
Hence,
char ( * ( * f[3] ) ()) [5] ;
means f is an array of 3 pointers to function returning a pointer to array of 5 characters
How do I read this complex declaration in C?
Start with the leftmost identifier and work your way out, remembering that []
and ()
bind before *
, so *a[]
is an array of pointers, (*a)[]
is a pointer to an array, *f()
is a function returning a pointer, and (*f)()
is a pointer to a function:
signal -- signal
signal( ) -- is a function
signal( sig, ) -- with a parameter named sig
signal(int sig, ) -- of type int
signal(int sig, func ) -- and a parameter named func
signal(int sig, (*func) ) -- which is a pointer
signal(int sig, (*func)( )) -- to a function
signal(int sig, (*func)(int)) -- taking an int parameter
signal(int sig, void (*func)(int)) -- and returning void
*signal(int sig, void (*func)(int)) -- returning a pointer
(*signal(int sig, void (*func)(int)))( ) -- to a function
(*signal(int sig, void (*func)(int)))(int) -- taking an int parameter
void (*signal(int sig, void (*func)(int)))(int); -- and returning void
signal
associates a signal handler function func
with a signal sig
, and returns the pointer to the old signal handler function:
void new_interrupt_handler(int sig)
{
... // do something interesting with interrupt signal
}
int main(void)
{
void (*old_interrupt_handler)(int);
...
/**
* Set up our new interrupt handler
*/
old_interrupt_handler = signal(SIGINT, new_interrupt_handler);
...
/**
* Restore original interrupt handler
*/
signal(SIGINT, old_interrupt_handler);
...
}
How do I understand complicated function declarations?
As others have pointed out, cdecl is the right tool for the job.
If you want to understand that kind of declaration without help from cdecl, try reading from the inside out and right to left
Taking one random example from your list char (*(*X[3])())[5];
Start at X, which is the identifier being declared/defined (and the innermost identifier):
char (*(*X[3])())[5];
^
X is
X[3]
^^^
X is an array of 3
(*X[3])
^ /* the parenthesis group the sub-expression */
X is an array of 3 pointers to
(*X[3])()
^^
X is an array of 3 pointers to function accepting an unspecified (but fixed) number of arguments
(*(*X[3])())
^ /* more grouping parenthesis */
X is an array of 3 pointers to function accepting an unspecified (but fixed) number of arguments and returning a pointer
(*(*X[3])())[5]
^^^
X is an array of 3 pointers to function accepting an unspecified (but fixed) number of arguments and returning a pointer to an array of 5
char (*(*X[3])())[5];
^^^^ ^
X is an array of 3 pointers to function accepting an unspecified (but fixed) number of arguments and returning a pointer to an array of 5 char.
Complex type declaration with an anonymous profile as a parameter
In int (*replace_f(int (*func)(int, int)))(int, int);
, the declaration of func
has function prototype scope because it appears inside a function declaration. So this declaration declares two identifiers, replace_f
and func
, but the scope of func
ends at the end of the function declaration.
That makes func
useless in this case. There are situations where an identifier in function prototype scope is useful, such as void foo(int x, int y, float a[x][y]);
, where x
and y
are used to describe the dimensions of a
.
But then, the author claims if we need to declare the type pointer to the early function we have to declare as: … not as …
This is incorrect. You can declare ptr_replace
in any of the three ways shown.
He claims that it's not available to use two or more identifiers in the type declaration. Why does it work then?
It does work to declare replace_f
. It does not work to declare func
or any_other_identifier
. So perhaps the original text meant something like this?
Related Topics
C++ Static Template Member, One Instance for Each Template Type
Designated Initializers in C++20
At What Point Does Dereferencing the Null Pointer Become Undefined Behavior
Recommended Values for Opencv Detectmultiscale() Parameters
New to Xcode Can't Open Files in C++
How to Check If the Program Is Run from a Console
Invalid Use of Incomplete Type
Why Is Copy Constructor Called Instead of Conversion Constructor
If I Do a 'Typedef' in C or C++, When Should I Add '_T' at the End of Typedef'Ed Type
Forwarding All Constructors in C++0X
Write Concurrently Vector<Bool>
Rewinding Std::Cout to Go Back to the Beginning of a Line
Calling a Virtual Function from the Constructor
The New Keyword "Auto"; When Should It Be Used to Declare a Variable Type
What Is the C++ Function to Raise a Number to a Power
C++: Deep Copying a Base Class Pointer
C++11 - Declaring Non-Static Data Members as 'Auto'
Will a "Variablename;" C++ Statement Be a No-Op at All Times