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

时间:2010-11-05 16:32:46

标签: c++ c function-pointers

正如我在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
    都有效?
  • 我在
    warning: assignment from incompatible pointer type
    的第21行(fs = x();)收到警告。如何删除此警告?

ADDED

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

#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 个答案:

答案 0 :(得分:3)

您必须决定是使用C还是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

即。具有指向数组的指针类型(注意与函数声明的相似性)。并且为了通过这样的指针调用函数,你必须做

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

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


或者,您可以停止使用指针到数组类型,而是使用指针到指针类型。在这种情况下,您的函数应定义如下

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

并在main中,您将按照以下方式使用

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

请注意,此main与您原始帖子中的内容相同。换句话说,您的原始代码是两种不同的绝对不兼容技术的奇异融合。你必须决定使用哪一个并坚持下去。

答案 1 :(得分:2)

我建议你输入你的函数指针,否则很难看出发生了什么。

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();

答案 2 :(得分:1)

对于第一个问题,

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的函数的指针数组。通过添加&amp;,您现在实际上返回指向返回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

答案 3 :(得分:1)

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

答案 4 :(得分:1)

执行T a[] = { .. };后,a被声明为T[N]类型,但不是类型T[]

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

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

它会限制您可以返回到特定大小的内容。这是C ++与C的不同之处,它允许您将T(*)[N]分配给T(*)[]。 C ++没有这种所谓的“类型兼容性”规则。如果你想摆脱&的需要,你需要返回数组的衰变类型。数组的元素类型是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;
}