简体   繁体   English

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

[英]Messy function pointer : how to remove the warning?

As I asked and answered in this post . 正如我在这篇文章中提到并回答的那样。 I have the following example code. 我有以下示例代码。

#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 are 我的问题是

  • Why the 为什么
     return funclist (with "warning: return from incompatible pointer type") return funclist(带有“警​​告:从不兼容的指针类型返回”) 
    and
     return &funclist 回归和娱乐 
    both works? 两者都有效?
  • I get warning at the line 21 (fs = x();) of 我在第21行(fs = x();)得到警告
     warning: assignment from incompatible pointer type 警告:从不兼容的指针类型分配 
    . How to remove this warning? 如何删除此警告?

ADDED 添加

With AndreyT's help. 有了AndreyT的帮助。 I could get the following code that doesn't have the 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 messy code with the help from peoro. 在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]()); 
}

You have to decide whether you are using C or C++. 您必须决定是使用C还是C ++。 These languages are significantly different in their treatment of the situations like yours. 这些语言在处理像你这样的情况时有很大的不同。

In C++ a "pointer to an [] array" (ie an array of unspecificed size) is a completely different type from a "pointer to an [N] array" (ie an array of specified size). 在C ++中,“指向[]数组的指针”(即未指定大小的数组)是与“指向[N]数组的指针”(即指定大小的数组)完全不同的类型。 This immediately means that your code has no chance to compile as C++ code. 这立即意味着您的代码无法编译为C ++代码。 It is not a "warning", it is an error. 它不是“警告”,而是一个错误。 If you want your code to compile as C++, you need to specfiy the exact array size in the function return type 如果希望代码编译为C ++,则需要在函数返回类型中指定确切的数组大小

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

And, of course, you have to return &funclist , since you are declaring your function as returning a pointer to an array . 当然,你必须返回&funclist ,因为你声明你的函数返回一个指向数组指针

In main declaring the receiving pointer as char (**fs)() makes no sense whatsoever. main声明接收指针为char (**fs)()没有任何意义。 The function is returning a pointer to an array , not a pointer to a pointer . 该函数返回一个指向数组指针 ,而不是指向指针的指针 You need to declare your fs as 你需要声明你的fs

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

ie as having pointer-to-array type (note the similarity to the function declaration). 即具有指向数组的指针类型(注意与函数声明的相似性)。 And in order to call the function through such a pointer you have to do 并且为了通过这样的指针调用函数,你必须这样做

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

In C language the explicit array size in the pointer-to-array declarations can be omitted, since in C "pointer to an [] array" type is compatible with "pointer to an [N] array" type, but the other points still stand. 在C语言中,指针到数组声明中的显式数组大小可以省略,因为在C“指向[]数组的指针”类型与“指向[N]数组”类型的指针兼容,但其他点仍然支架。 However, even in C it might make more sense to specify that size explicitly. 但是,即使在C中,明确指定该大小也许更有意义。


Alternatively, you can stop using pointer-to-array type and instead use pointer-to-pointer type. 或者,您可以停止使用指针到数组类型,而是使用指针到指针类型。 In that 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'll work with it as follows main您将按照以下方式使用它

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

Note, that this main is the same as what you had in your original post. 请注意,此main内容与原始帖子中的内容相同。 In other words, your original code is a bizarre fusion of two different absolutely incompatible techniques. 换句话说,您的原始代码是两种不同的绝对不兼容技术的奇异融合。 You have to decide which one you want to use and stick to it. 您必须决定要使用哪一个并坚持下去。

I'd suggest you to typedef your function pointer, otherwise it's hard to see what's happening. 我建议你输入你的函数指针,否则很难看出发生了什么。

typedef char (*funptr)();

Anyway, x returns a pointer to char (*(*x())[]) , and funclist is not that thing. 无论如何, x返回一个指向char (*(*x())[])的指针,并且funclist不是那个东西。

Same for fs=x(); 对于fs=x(); : char ( ( ())[]) != char (**)(); char ( ( ())[]) != char (**)(); ... ...

If I'm not wrong there are also some errors with precedence between [] and *... 如果我没错,那么[]和*之间也会出现一些优先级错误...

This is working 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();

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

So the expected return type of x is a pointer to an array of pointers to functions returning char, but what you're returning is just an array of pointers to functions returning char. 所以x的预期返回类型是指向返回char的函数的指针数组的指针,但是你返回的只是指向返回char的函数的指针数组。 By adding the &, you are now in fact returning a pointer to the array of pointers to functions returning char. 通过添加&,您现在实际上返回指向返回char的函数的指针数组的指针。

For the second, again the expected return type of x is a pointer to an array of pointers to functions returning char, but we see 对于第二个,x的预期返回类型是指向返回char的函数的指针数组的指针,但我们看到了

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

What you want instead is char (*(*fs)[])(); 你想要的是char (*(*fs)[])();

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

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

When you do T a[] = { .. }; 当你做T a[] = { .. }; then a is declared as having type T[N] , but not as having type T[] . 然后a被声明为具有类型T[N] ,但不具有类型T[]

So you need to put some number in the brackets. 所以你需要在括号中加上一些数字。

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

It will limit what you can return to a specific size. 它将限制您可以返回到特定大小的内容。 This is where C++ differs from C, which will allow you to assign a T(*)[N] to an T(*)[] . 这是C ++与C的不同之处,它允许您将T(*)[N]分配给T(*)[] C++ has no such so-called "type compatibility" rules. C ++没有这种所谓的“类型兼容性”规则。 If you want to get rid of the need for the & , you need to return the decay-type of the array. 如果你想摆脱对&的需要,你需要返回数组的衰变类型。 The element type of your array is char(*)() 数组的元素类型是char(*)()

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

Using an identity template you can make your declaration look much 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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM