我只是在浏览Internet上的一些代码后发现:
float * (*(*foo())[SIZE][SIZE])()
我如何阅读此声明?是否有一组特定的规则来读取这种复杂的声明?
我只是在浏览Internet上的一些代码后发现:
float * (*(*foo())[SIZE][SIZE])()
我如何阅读此声明?是否有一组特定的规则来读取这种复杂的声明?
Answers:
我已经有一段时间没有这样做了!
开始,foo
然后继续。
float * (*(*
foo()
)[SIZE][SIZE])()
foo是一个没有参数的函数...
括号括起来,无法正确执行。往左走:
float * (*(
* foo()
)[SIZE][SIZE])()
foo是一个不带参数的函数,不返回指针
不能再往左走,所以我们越过括号再往右走
float * (*
(* foo())
[SIZE][SIZE])()
float * (*
(* foo())[SIZE]
[SIZE])()
float * (*
(* foo())[SIZE][SIZE]
)()
foo是一个不带参数的函数,它返回一个指向SIZE数组的指针...
结束括号已到达,再次向左到达指针符号:
float * (
*(* foo())[SIZE][SIZE]
)()
foo是一个不带参数的函数,它返回一个指向SIZE数组的指针。
再次左括号,所以我们越过它并再次右行:
float *
( *(* foo())[SIZE][SIZE])
()
float *
( *(* foo())[SIZE][SIZE])()
foo是一个不带参数的函数,它返回一个指向SIZE数组的指针。
并留到最后
float * ( *(* foo())[SIZE][SIZE])()
foo是一个不带参数的函数,不返回指向SIZE数组的指针。SIZE指针的数组。不带参数的函数,不返回指向浮点数的指针。
无论写什么,请教他使用typedef
:
// Function that returns a pointer to float
typedef float* PFloatFunc ();
// Array of pointers to PFloatFunc functions
typedef PFloatFunc* PFloatFuncArray2D[SIZE][SIZE];
// Function that returns a pointer to a PFloatFuncArray2D
PFloatFuncArray2D* foo();
标准规则:找到最左边的标识符,然后出路,记住[]
并()
绑定到*
:
foo -- foo
foo() -- is a function
*foo() -- returning a pointer
(*foo())[SIZE] -- to a SIZE-element array
(*foo())[SIZE][SIZE] -- of SIZE-element arrays
*(*foo())[SIZE][SIZE] -- of pointers
(*(*foo())[SIZE][SIZE])() -- to functions
* (*(*foo())[SIZE][SIZE])() -- returning pointers
float * (*(*foo())[SIZE][SIZE])(); -- to float
因此,假设您有一堆返回指针的函数float
:
float *quux();
float *bar();
float *bletch();
float *blurga();
假设您要将它们存储在2x2表中:
float *(*tab[SIZE][SIZE])() = {quux, bar, bletch, blurga};
tab
是指向函数的指针的SIZE x SIZE数组,返回指向的指针float
。
现在让我们决定我们要一个函数返回一个指向该表的指针:
float *(*(*foo())[SIZE][SIZE])()
{
static float *(*tab[SIZE][SIZE])() = {quux, bar, bletch, blurga};
return &tab;
}
请注意,您可能有几个函数可以构建具有不同功能的表,或者以不同的方式组织相同的功能:
float *(*(*qwerbl())[SIZE][SIZE])()
{
static float *(*tab[SIZE][SIZE])() = {blurga, bletch, bar, quux};
return tab;
}
这是我可以想到的唯一原因。您不应该经常在野外看到这样的类型(尽管它们确实偶尔出现,并且我犯了写类似令人发指的东西的罪行)。
通常,您可以尝试cdecl.org,但需要替换为SIZE
假设您将其交换SIZE
为12,您将获得:
将foo声明为函数,该函数返回指向数组12的指针的指针,该指针指向函数的数组12
我不确定这是否对您有帮助!
这里有两个观察结果:
该文档为我提供了有关如何轻松准备任何C声明的最佳线索:
http://c-faq.com/decl/spiral.anderson.html
遵循三个简单步骤:
从未知元素开始,沿螺旋/顺时针方向移动;在遇到以下要素时,将其替换为相应的英文陈述:
[X]
或[]
=>数组X大小为...或数组未定义大小为...
(type1, type2)
=>函数传递type1和type2返回...
*
=>指向...的指针继续以螺旋/顺时针方向执行此操作,直到所有令牌都被覆盖。
始终首先用括号解决任何问题!
范例:
+-------+
| +-+ |
| ^ | |
char *str[10];
^ ^ | |
| +---+ |
+-----------+
Question we ask ourselves: What is str?
``str is an...
- We move in a spiral clockwise direction starting with `str' and the first character we see is a `[' so, that means we have an array, so...
``str is an array 10 of...
- Continue in a spiral clockwise direction, and the next thing we encounter is the `*' so, that means we have pointers, so...
``str is an array 10 of pointers to...
- Continue in a spiral direction and we see the end of the line (the `;'), so keep going and we get to the type `char', so...
``str is an array 10 of pointers to char''
We have now ``visited'' every token; therefore we are done!
尽管上面的大多数答案都足够好,但是仍然缺少用于解码复杂C声明的完整规则集。我在下面提供了一套完整的程序来解码任何复杂的C声明。这套规则实际上是基于运算符的优先级。可以将诸如右手螺旋规则之类的规则视为这些规则集的捷径。
首先,我们需要了解一些对声明进行解码的知识。
声明的“基本类型”
AC声明始终只有一种基本声明类型。这是声明的最左侧。例如 -
int a
-基本类型为“ int”float *p
-基本类型为“浮动”char (*p)[3]
-基本类型为“字符”优先性和关联性
接下来,我们需要知道的优先顺序()
,[]
以及*
-引用操作
()
,[]
-关联从左到右*
-关联性从右到左对应于上述每个运算符的短语
接下来,我们需要知道与每个运算符相对应的解码短语。前面的示例将阐明这一点。
()
-函数返回[SIZE]
-SIZE数组*
-指向现在按照以下规则解码声明
始终先写变量名,后跟“ is”。
例如 -
int a
-是...float *p
- p是...char (*p)[3]
- p是...总是以基本类型结尾
例如 -
int a
-一个是... INTfloat *p
- p是...浮动char (*p)[3]
- p是...焦炭现在,使用以下子步骤填充这部分内容
从名称开始,按照运算符的优先级和关联性选择下一个优先级最高的运算符,并将与之相对应的短语附加到解码字符串的中间部分。
对剩余的声明重复上述子步骤,直到解码过程完成
注意1: 为简单起见,我忽略了函数的参数,但是可以将其包含在与相对应的短语之后()
。
注2:()
与任何算术表达式一样, Parenthesis()更改运算符的优先级顺序。
注意3: 您可以在解码的声明中使用括号来增加可读性(我在下面的一些示例中已经做到了)。将()的每组视为一个单元。
注4: n维数组实际上是...(n-1次)array的数组。对于ex-int A [2] [3]-A是2的数组(3 int的数组),即A是2个元素的数组,其中每个元素是包含3个整数的数组
例子
int a
- 一个intfloat *p
- p是指针浮char (*p)[3]
-p是指向3个字符的数组的指针一些复杂的声明示例
int **p[10]
-p是10指向int的指针的数组int (*p)[10]
-p是10整数数组的指针int *p(char *a)
-p是返回int指针的函数int (*p(char*a))[10]
-p是函数返回(指向(10个整数的数组)的指针)int *(*p)()
-p是指向(函数返回(指向int的指针))的指针int (*p()[20])[10]
-p是返回的函数(数组为20(指向(数组为10 int的指针)))这组规则也可以使用const
-const限定符将其左侧的术语(如果存在)修改,否则将其右侧的术语修改。
const int *p[10]
-p是指向int const的10指针的数组int const *p[10]
-p是指向const int的10指针的数组(与第7个示例相同)int *const p[10]
-p是10个指向int的const指针的数组现在,一个非常复杂的示例在实践中不会在任何地方使用,但是仍然可以用来演示解码过程
char *(*(**foo[][8])())[]
-foo是(8的数组(指向(函数返回的指针(指向(char的指针的数组))的指针))))的数组)现在最后解码问题中给出的声明
float * (*(*foo())[SIZE][SIZE])()
-foo是函数返回(指向(SIZE数组(SIZE数组(指向(函数返回指向float的指针))的指针))的指针))
以下是我从中阅读此解码过程的文章的链接
示例10摘自本文
将foo声明为函数,返回指向数组SIZE的指针,数组的指向SIZE的指针返回给float的函数的指针