Conditional function pointer: how to remove a warning?

As I asked and answered in this message . I have the following code example.

#include <stdio.h> char foo() { return 'a'; } char bar() { return 'b'; } char blurga() { return 'c'; } char bletch() { return 'd'; } char (*gfunclist[])() = {foo, bar, blurga, bletch}; char (*(*x())[])() { static char (*funclist[4])() = {foo, bar, blurga, bletch}; return funclist; } int main() { printf("%c\n",gfunclist[0]()); char (**fs)(); fs = x(); printf("%c\n",fs[1]()); } 

My questions

  • Why do they work
      return funclist (with "warning: return from incompatible pointer type") 
    and
      return & funclist 
    ?
  • I get a warning on line 21 (fs = x ();) of
      warning: assignment from incompatible pointer type 
    . How to remove this warning?

ADDED

Using AndreyT. I could get the following code that has no warnings.

 #include <stdio.h> char foo() { return 'a'; } char bar() { return 'b'; } char blurga() { return 'c'; } char bletch() { return 'd'; } char (*gfunclist[])() = {foo, bar, blurga, bletch}; char (*(*x())[])() { static char (*funclist[4])() = {foo, bar, blurga, bletch}; return &funclist; } int main() { printf("%c\n",gfunclist[0]()); char (*(*fs)[4])(); fs = x(); printf("%c\n",(*fs)[1]()); } 

And this is less dirty code with peoro.

 typedef char (*funptr)(); funptr gfunclist[] = {foo, bar, blurga, bletch}; funptr* x() { static funptr funclist[4] = {foo, bar, blurga, bletch}; return funclist; } int main() { printf("%c\n",gfunclist[0]()); funptr *fs; fs = x(); printf("%c\n",fs[1]()); } 
+4
c ++ c function-pointers
source share
5 answers

You must decide if you are using C or C ++. These languages ​​vary widely in situations like yours.

In C ++, a "pointer to an array [] " (i.e. an array of indefinite size) is a completely different type from a "pointer to an array [N]" (i.e. an array of a specified size). This immediately means that your code is not able to compile C ++ code. This is not a warning, this is a mistake. If you want your code to compile as C ++, you need to specify the size of the exact array in the return type of the function

 char (*(*x())[4])() // <- see the explicit 4 here? { static char (*funclist[4])() = {foo, bar, blurga, bletch}; return &funclist; } 

And, of course, you need to return &funclist , since you are declaring your function as returning a pointer to an array.

In main declaring the receiving pointer as char (**fs)() makes no sense. The function returns a pointer to an array, not a pointer to a pointer. You must declare your fs as

 char (*(*fs)[4])(); // <- pointer to an array 

i.e. as having the type of a pointer to an array (note the similarity to the function declaration). And to call a function through such a pointer, you must do

 printf("%c\n", (*fs)[1]()); 

In C, the explicit size of the array in the array pointer declarations can be omitted, since in the C pointer "for type [], the array is" compatible with "pointer to array type [N]", but the other items are still there. However, even in C, it may make sense to specify this size explicitly.


Alternatively, you can stop using the pointer-array type and use the pointer-to-pointer type instead. In this case, your function should be defined as follows

 char (**x())() { static char (*funclist[4])() = {foo, bar, blurga, bletch}; return funclist; // <- no `&` here } 

and in main you will work with it as follows

 char (**fs)(); fs = x(); printf("%c\n", fs[1]()); 

Please note that this main is the same as what you had in the original message. In other words, your source code is a fancy merger of two different completely incompatible methods. You must decide which one you want to use and stick to it.

+3
source share

I suggest you type a pointer to a function, otherwise it's hard to understand what is happening.

 typedef char (*funptr)(); 

In any case, x returns a pointer to char (*(*x())[]) , but funclist is not it.

The same for fs=x(); : char ((())[]) != char (**)(); ...

If I am not mistaken, there are also some errors with a priority between [] and * ...

This works fine:

 typedef char (*funptr)(); funptr gfunclist[] = {foo, bar, blurga, bletch}; funptr *x() { static funptr funclist[4] = {foo, bar, blurga, bletch}; return funclist; } funptr *fs; fs = x(); 
+2
source share

For the first question

 cdecl> explain char (*(*x())[])() declare x as function returning pointer to array of pointer to function returning char cdecl> explain static char (*funclist[4])() declare funclist as static array 4 of pointer to function returning char 

Thus, the expected return type of x is a pointer to an array of pointers to functions that return char, but the one you return is just an array of pointers to functions that return char. By adding &, you now actually return a pointer to an array of pointers to functions that return char.

For the second, again, the expected return type x is a pointer to an array of pointers to functions that return char, but we see

 cdecl> explain char (**fs)(); declare fs as pointer to pointer to function returning char 

Instead, you need char (*(*fs)[])();

 cdecl> explain char (*(*fs)[])(); declare fs as pointer to array of pointer to function returning char 
+1
source share

Select either * or [] in the return type x , not both.

+1
source share

When you execute T a[] = { .. }; , then a declared as having type T[N] , but not having type T[] .

So you need to put some number in brackets.

 char (*(*x())[sizeof(gfunclist)/sizeof(*gfunclist)])() { return &gfunclist; } 

It will limit what you can return to a specific size. Here C ++ is different from C, which allows you to assign T(*)[N] to T(*)[] . C ++ does not have these so-called type compatibility rules. If you want to get rid of the need for & , you need to return the type of array decay. The element type of your array is char(*)()

 char (**x())() { static char (*funclist[4])() = {foo, bar, blurga, bletch}; return funclist; } 

Using an identification template, you can make your declaration more readable.

 template<typename T> struct identity { typedef T type; }; identity<char()>::type **x() { static identity<char()>::type *funclist[] = {foo, bar, blurga, bletch}; return funclist; } 
+1
source share

All Articles