代码之家  ›  专栏  ›  技术社区  ›  prosseek

凌乱的函数指针:如何删除警告?

  •  4
  • prosseek  · 技术社区  · 14 年前

    我问了又答 this post . 我有下面的示例代码。

    #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]()); 
    }
    

    • 为什么
      return funclist (with "warning: return from incompatible pointer type")
      return &funclist
    • 我在第21行(fs=x();)收到警告
      warning: assignment from incompatible pointer type

    补充

    在安德烈的帮助下。我可以得到以下没有警告的代码。

    #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]()); 
    }
    

    在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]()); 
    }
    
    5 回复  |  直到 7 年前
        1
  •  3
  •   AnT stands with Russia    14 年前

    你必须决定你是用C还是C++。这些语言在处理像你这样的情况上有很大的不同。

    [] 数组(即未指定大小的数组)与“指向[N]数组的指针”(即指定大小的数组)是完全不同的类型。这意味着您的代码没有机会编译为C++代码。这不是“警告”,而是一个错误。如果希望将代码编译为C++,则需要在函数返回类型中指定精确的数组大小。

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

    当然,你得回去 &funclist 指向数组的指针 .

    main 将接收指针声明为 char (**fs)() 毫无意义。函数返回 指向数组的指针 指向指针的指针 . 你需要申报 fs

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

    i、 e.有 指向数组的指针 类型(注意与函数声明的相似性)。为了通过这样的指针调用函数

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

    在C语言中,可以省略指向数组声明的指针中的显式数组大小,因为在C语言中,“指向[]数组的指针”类型与“指向[N]数组的指针”类型兼容,但其他点仍然存在。然而,即使在C语言中,显式地指定这个大小也可能更有意义。


    指向指针的指针 键入。在这种情况下,您的函数定义如下

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

    主要的 你将按如下方式处理它

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

    主要的

        2
  •  2
  •   peoro    14 年前

    我建议您输入定义函数指针,否则很难看到发生了什么。

    typedef char (*funptr)();
    

    不管怎样, x 返回指向 char (*(*x())[]) ,和 funclist

    同样适用于 fs=x(); : char ( ( ())[]) != char (**)(); ...

    这很管用:

    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();
    
        3
  •  1
  •   user470379    14 年前

    对于第一个问题,

    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
    

    因此x的预期返回类型是指向返回char的函数的指针数组的指针,但返回的只是指向返回char的函数的指针数组。通过添加&您现在实际上是在返回指向返回char的函数的指针数组的指针。

    第二种情况下,x的预期返回类型是指向返回char的函数的指针数组的指针,但是我们看到

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

    char (*(*fs)[])();

    cdecl> explain char (*(*fs)[])();
    declare fs as pointer to array of pointer to function returning char
    
        4
  •  1
  •   Ben Jackson    14 年前

    选择额外的 * 或者 [] 在返回类型中 x ,不是两者都有。

        5
  •  1
  •   Johannes Schaub - litb    14 年前

    当你这样做的时候 T a[] = { .. }; 然后 a 声明为具有类型 T[N] ,但不是有类型 T[] .

    所以你需要在括号里加上一些数字。

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

    它将限制您可以返回到特定大小的内容。这是C++与C不同的地方,它允许你分配一个 T(*)[N] 给一个 T(*)[] & ,需要返回数组的衰退类型。数组的元素类型是 char(*)()

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

    使用标识模板可以使声明看起来可读性更强

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