复杂的指针表达式

时间:2014-12-19 17:15:26

标签: c++ pointers function-pointers

我一直在阅读在C ++ vol1中思考,并且有一个名为复杂声明&定义,描述了以下表达式,我无法理解:

void * (*(*fp1)(int))[10];
float (*(*fp2)(int,int,float))(int);

任何人都可以解释这些表达的含义,以及你如何解决这些表达式?

布鲁斯给出的解释如下:

  

fp1是一个指向函数的指针,该函数接受一个整数参数并返回一个指向10个void指针数组的指针。

     

fp2是一个指向函数的指针,该函数接受三个参数(int, int, and float)并返回一个指向函数的指针,该函数接受一个整数参数并返回float

虽然我已经发布了正确答案,但如果有人能够逐步演示这些表达式的解码,我将不胜感激。

5 个答案:

答案 0 :(得分:5)

这里有一个经验法则:从变量的名称开始,向右扫描直到到达)或声明的结尾,然后向左扫描直到到达(或开始定义然后重复。

因此,对于第一个示例,请从名称fp1开始。向右看,你看到),现在向左看。您看到*,因此您知道fp1是指针。然后你到达(,然后再向右走。右边的下一个字符是(,表示功能。括号内是int,因此该函数采用int参数。所以到目前为止,你有一个"指向函数的指针,它带有一个int参数"接下来,你到达另一个),所以左转。您看到*,因此返回类型是指针。接下来您会遇到(,因此您转到右侧查看[10]。当然,这意味着一个大小为10的数组。所以现在你有一个指向函数的指针,该函数接受int参数并返回一个指向大小为10的数组的指针。现在你位于最右边,所以扫描离开,你遇到void*。所以从这里开始,你有一个指向函数的指针,该函数接受int参数并返回一个指向包含void指针的大小为10的数组的指针。"

对于第二个例子,请遵循类似的程序。

答案 1 :(得分:3)

void * (*(*fp1)(int))[10];垂直排列。我将X YZ用于我们已解码的表达式的部分内容。

void * (
  *(
    *fp1
  )
  (int)
)[10]
解除引用(fp1)时

*fp1

void * (
  *X
  (int)
)[10]

采用返回值为

的int X(int)的函数
void * (
  *Y
)[10]
<\ n>取消引用时*Y

void* Z[10]

[10]个元素的数组,每个元素都是void*

float (*(*fp2)(int,int,float))(int);

float (
  *(*fp2)(int,int,float)
)(int);
取消引用时{p> fp2 *fp2

float (
  *X(int,int,float)
)(int);

是一个需要int, int, float

的函数
float (
  *Y
)(int);

取消引用时的返回值:

float Z(int);

是一个接受int并返回float的函数。

现在大部分都是你已经知道的理由。

然而,这是一项几乎无用的技能。关于这种技能的唯一好处就是能够解码中等复杂的链接器编译器错误(任何过去中等复杂的事物,无论如何都要使用工具)。

如果它在代码中,则可以在上述工具的帮助下修复代码。如果出现错误,请使用工具对其进行解码。使用该工具将更加可靠,因为这是您想要做的一件罕见的事情,速度成本并不重要(除非,例如,当互联网出现故障时你有一个错误,你无法得到这样的在那个狭窄的情况下,你拉出一些静态断言,你就可以一点一点地学习它。

答案 2 :(得分:1)

每当您遇到这样复杂的表达时,您需要遵循左右规则

从标识符开始,然后继续向右 - 左 - 右 - 左移动......

例如,

void * (*(*fp1)(int))[10];
           ^^^

fp1是......

void * (*(*fp1)(int))[10];
              ^

fp1是...... (现在离开,因为我们点了一个近距离)

void * (*(*fp1)(int))[10];
          ^

fp1指向...

void * (*(*fp1)(int))[10];
               ^^^^^

fp1是指向带有整数参数的函数的指针并返回...

void * (*(*fp1)(int))[10];
        ^

fp1是指向函数的指针,该函数采用整数参数并返回指向...

的指针
void * (*(*fp1)(int))[10];
                     ^^^^

fp1是指向带有整数参数的函数的指针,并返回指向数组10 ...

的指针
void * (*(*fp1)(int))[10];
^^^^^^

fp1是指向带有整数参数的函数的指针,并返回指向10个无效指针数组的指针。

对于另一个例子,使用相同的技术。

但在现实世界中,只需使用http://cdecl.org/即可为您简化工作。

对于void * (*(*fp1)(int))[10];,它将结果显示为

  

将fp1声明为指向function(int)的指针,返回指向void

的指针数组10的指针

答案 3 :(得分:1)

  

任何人都可以解释这些表达的含义,以及你如何解决这些表达式?

一般情况下,你没有。从某种意义上说,这些是“只写”声明。任何第一次在生产代码中使用它的人都应该收到警告;第二次使用这样的东西应被认为是射击的原因。

你可以通过对它们应用一组relatively straightforward rules来理解它们,但更好的选择是将它们提供给cdecl.org,并立即得到答案。对我来说,这类似于五位数的乘数:任何从三年级毕业的人都可以用铅笔和纸做,但使用计算器可以节省很多时间。

但是,这并不意味着应该依靠cdecl来理解代码。相反,应该首先避免编写这样的代码。幸运的是,C和C ++提供了一种避免这种声明的好方法:不是一次编写整个东西,而是编写它的部分。

首先,为“十个无效指针数组”声明一个类型,如下所示:

typedef void* (TenVoidPtrs)[10];

然后,为“指向函数的指针指定一个int并返回一个包含十个void指针的数组”的类型声明:

typedef TenVoidPtrs*(*RetPtrTenVoid)(int)

使用TenVoidPtrs类型,这也非常简单。假设您为类型提供描述性名称,则无需使用cdecl检查声明的类型:即使是第一次看到您的代码的人也应该非常清楚:

RetPtrTenVoid fPtr = ...

答案 4 :(得分:1)

这不是解析它的解决方法,而是写什么 从c ++ 11开始,有一种更简单的方法来创建这些typedef

using Func_I_F = auto (*)(int) -> float;

using Func_IIF_FIF = auto (*)(int,int,float) -> Func_I_F;

Func_IIF_FIF fp2;

fp2的类型与你写的相同。