复杂的函数声明

http://www.cnblogs.com/answeryi/archive/2012/07/30/2615409.html

http://www.codeproject.com/Articles/7042/How-to-interpret-complex-C-C-declarations

char *(*(*var[10])())(); 的声明可以如下分解:(从内到外,从右到左,依次typedef)

e var[10];         // var is an array of 10 pointers to
                   // functions returning pointers to
                   // functions returning pointers to chars.

typedef d *e;      // e is a pointer to a function
                   // returning  a pointer to a
                   // function that returns a
                   // pointer to a char

typedef c d();     // d is a function returning
                   // a pointer to a function
                   // that returns a pointer to a char

typedef b *c;      // c is a pointer to a function
                   // that returns a pointer to a char

typedef a b();     // b is a function that returns
                   // a pointer to a char

//这里很有意思,typedef int b(); 表示该函数的返回类型是int;

typedef char * a;  // a is a pointer to a char

How to interpret complex C/C++ declarations

Vikram A Punathambekar,                          3 Jul 2004                                      CPOL

   4.73 (160 votes)

1


2


3


4


5

4.73/5 - 160 votes

4 removed

μ 4.59, σa 1.54 [?]

Rate this:

Please Sign up or sign in to vote.

Ever came across a declaration like int * (* (*fp1) (int) ) [10]; or something similar that you couldn‘t fathom? This article will teach you to interpret such complex C/C++ declarations, including the use of typedef, const, and function pointers.

Contents

Introduction

Ever came across a declaration like int * (* (*fp1) (int) ) [10]; or something similar that you couldn‘t fathom? This article will teach you to interpret C/C++ declarations, starting from mundane ones (please bear with me here) and moving on to very complex ones. We shall see examples of declarations that we come across in everyday life, then move on to the troublesome const modifier and typedef, conquer function pointers, and finally see the right-left rule, which will allow you to interpret any C/C++ declaration accurately. I would like to emphasize that it is not considered good practice to write messy code like this; I‘m merely teaching you how to understand such declarations. Note: This article is best viewed with a minimum resolution of 1024x768, in order to ensure the comments don‘t run off into the next line.

[Back to contents]

The basics

Let me start with a very simple example. Consider the declaration:

int n;

This should be interpreted as "declare n as an int".

Coming to the declaration of a pointer variable, it would be declared as something like:

int *p;

This is to be interpreted as "declare p as an int * i.e., as a pointer to an int". I‘ll need to make a small note here - it is always better to write a pointer (or reference) declaration with the * (or &) preceding the variable rather than following the base type. This is to ensure there are no slip-ups when making declarations like:

int* p,q;

At first sight, it looks like p and q have been declared to be of type int *, but actually, it is only p that is a pointer, q is a simple int.

We can have a pointer to a pointer, which can be declared as:

char **argv;

In principle, there is no limit to this, which means you can have a pointer to a pointer to a pointer to a pointer to a float, and so on.

Consider the declarations:

int RollNum[30][4];
int (*p)[4]=RollNum;
int *q[5];

Here, p is declared as a pointer to an array of 4 ints, while q is declared as an array of 5 pointers to integers.

We can have a mixed bag of *s and &s in a single declaration, as explained below:

int **p1;  //  p1 is a pointer   to a pointer   to an int.
int *&p2;  //  p2 is a reference to a pointer   to an int.
int &*p3;  //  ERROR: Pointer    to a reference is illegal.
int &&p4;  //  ERROR: Reference  to a reference is illegal.

[Back to contents]

The const modifier

The const keyword is used when you want to prevent a variable (oops, that‘s an oxymoron) from being modified. When you declare a const variable, you need to initialize it, because you can‘t give it a value at any other time.

const int n=5;
int const m=10;

The two variables n and m above are both of the same type - constant integers. This is because the C++ standard states that the const keyword can be placed before the type or the variable name. Personally, I prefer using the former style, since it makes the const modifier stand out more clearly.

const is a bit more confusing when it comes to dealing with pointers. For instance, consider the two variables p and q in the declaration below:

const int *p;
int const *q;

Which of them is a pointer to a const int, and which is a const pointer to an int? Actually, they‘re both pointers to const ints. A const pointer to an int would be declared as:

int * const r= &n; // n has been declared as an int

Here, p and q are pointers to a const int, which means that you can‘t change the value of *p. r is a const pointer, which means that once declared as above, an assignment like r=&m; would be illegal (where m is another int) but the value of *r can be changed.

To combine these two declarations to declare a const pointer to a const int, you would have to declare it as:

const int * const p=&n // n has been declared as const int

The following declarations should clear up any doubts over how const is to be interpreted. Please note that some of the declarations will NOT compile as such unless they are assigned values during declaration itself. I have omitted them for clarity, and besides, adding that will require another two lines of code for each example.

char ** p1;                    //        pointer to       pointer to       char
const char **p2;               //        pointer to       pointer to const char
char * const * p3;             //        pointer to const pointer to       char
const char * const * p4;       //        pointer to const pointer to const char
char ** const p5;              //  const pointer to       pointer to       char
const char ** const p6;        //  const pointer to       pointer to const char
char * const * const p7;       //  const pointer to const pointer to       char
const char * const * const p8; //  const pointer to const pointer to const char

[Back to contents]

The subtleties of typedef

typedef allows you a way to overcome the *-applies-to-variable-not-type rule. If you use a typedef like:

typedef char * PCHAR;
PCHAR p,q;

both p and q become pointers. If the typedef had not been used, q would be a char, which is counter-intuitive.

Here are a few declarations made using typedef, along with the explanation:

typedef char * a;  // a is a pointer to a char

typedef a b();     // b is a function that returns
                   // a pointer to a char

typedef b *c;      // c is a pointer to a function
                   // that returns a pointer to a char

typedef c d();     // d is a function returning
                   // a pointer to a function
                   // that returns a pointer to a char

typedef d *e;      // e is a pointer to a function
                   // returning  a pointer to a
                   // function that returns a
                   // pointer to a char

e var[10];         // var is an array of 10 pointers to
                   // functions returning pointers to
                   // functions returning pointers to chars.

typedefs are usually used with structure declarations as shown below. The following structure declaration allows you to omit the struct keyword when you create structure variables even in C, as is normally done in C++.

typedef struct tagPOINT
{
    int x;
    int y;
}POINT;

POINT p; /* Valid C code */

[Back to contents]

Function pointers

Function pointers are probably the greatest source of confusion when it comes to interpreting declarations. Function pointers were used in the old DOS days for writing TSRs; in the Win32 world and X-Windows, they are used in callback functions. There are lots of other places where function pointers are used: virtual function tables, some templates in STL, and Win NT/2K/XP system services. Let‘s see a simple example of a function pointer:

int (*p)(char);

This declares p as a pointer to a function that takes a char argument and returns an int.

A pointer to a function that takes two floats and returns a pointer to a pointer to a char would be declared as:

char ** (*p)(float, float);

How about an array of 5 pointers to functions that receive two const pointers to chars and return a void pointer?

void * (*a[5])(char * const, char * const);

[Back to contents]

The right-left rule [Important]

This is a simple rule that allows you to interpret any declaration. It runs as follows:

Start reading the declaration from the innermost parentheses, go right, and then go left. When you encounter parentheses, the direction should be reversed. Once everything in the parentheses has been parsed, jump out of it. Continue till the whole declaration has been parsed.
One small change to the right-left rule: When you start reading the declaration for the first time, you have to start from the identifier, and not the innermost parentheses.

Take the example given in the introduction:

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

This can be interpreted as follows:

  1. Start from the variable name -------------------------- fp1
  2. Nothing to right but ) so go left to find * -------------- is a pointer
  3. Jump out of parentheses and encounter (int) --------- to a function that takes an int as argument
  4. Go left, find * ---------------------------------------- and returns a pointer
  5. Jump put of parentheses, go right and hit [10] -------- to an array of 10
  6. Go left find * ----------------------------------------- pointers to
  7. Go left again, find int -------------------------------- ints.

Here‘s another example:

int *( *( *arr[5])())();
  1. Start from the variable name --------------------- arr
  2. Go right, find array subscript --------------------- is an array of 5
  3. Go left, find * ----------------------------------- pointers
  4. Jump out of parentheses, go right to find () ------ to functions
  5. Go left, encounter * ----------------------------- that return pointers
  6. Jump out, go right, find () ----------------------- to functions
  7. Go left, find * ----------------------------------- that return pointers
  8. Continue left, find int ----------------------------- to ints.

[Back to contents]

Further examples

The following examples should make it clear:

float ( * ( *b()) [] )();              // b is a function that returns a
                                       // pointer to an array of pointers
                                       // to functions returning floats.

void * ( *c) ( char, int (*)());       // c is a pointer to a function that takes
                                       // two parameters:
                                       //     a char and a pointer to a
                                       //     function that takes no
                                       //     parameters and returns
                                       //     an int
                                       // and returns a pointer to void.

void ** (*d) (int &,
  char **(*)(char *, char **));        // d is a pointer to a function that takes
                                       // two parameters:
                                       //     a reference to an int and a pointer
                                       //     to a function that takes two parameters:
                                       //        a pointer to a char and a pointer
                                       //        to a pointer to a char
                                       //     and returns a pointer to a pointer
                                       //     to a char
                                       // and returns a pointer to a pointer to void

float ( * ( * e[10])
    (int &) ) [5];                    // e is an array of 10 pointers to
                                       // functions that take a single
                                       // reference to an int as an argument
                                       // and return pointers to
                                       // an array of 5 floats.

[Back to contents]

时间: 2024-10-29 04:11:14

复杂的函数声明的相关文章

深入理解javascript的作用域--函数声明为什么会前置

标签: javascript函数对象 这篇博文解决了以下迷惑 函数声明为什么前置 函数声明前置和变量前置优先级问题 为什么js文件开头就可以使用Math,String等库,而不需要导入头文件 1.变量对象VO 变量对象(Variable Object, 缩写为VO)是一个抽象 概念中的"对象",它用于存储执行上下文中的: 1. 变量 2. 函数声明 3. 函数参数 js解释器就是通过变量对象(VO)来找到我们定义的变量和函数的. 举个例子: var a = 10; function t

javascript 函数声明和函数表达式的区别(学习笔记)

javascript中声明函数的方法有两种:函数声明式和函数表达式. 区别如下: 1).以函数声明的方法定义的函数,函数名是必须的,而函数表达式的函数名是可选的. 2).以函数声明的方法定义的函数,函数可以在函数声明之前调用,而函数表达式的函数只能在声明之后调用. 3).以函数声明的方法定义的函数并不是真正的声明,它们仅仅可以出现在全局中,或者嵌套在其他的函数中,但是它们不能出现在循环,条件或者try/catch/finally中,而 函数表达式可以在任何地方声明. 下面分别用两种方法定义函数:

函数声明与函数表达式的区别

1.函数声明 函数声明以function关键字开头,接着是必须的函数(变量)名和以逗号分隔的可选的参数列表,再接着就是以大括号封装的函数体.函数声明必须是一个单独的JavaScript语句. 2.函数表达式 在任何情况下都是其它JavaScript语句的一部分(比如复制表达式等号的右侧.函数的参数)的函数被称为函数表达式. 3.比较 //函数声明function myFunctionDeclaration(){ function innerFunction() {} } //以下为函数表达式 v

函数声明与函数表达式

1.什么是函数声明,函数表达式 函数声明:function 函数名(){} 函数表达式:function 函数名(){}.函数名可写可不写.写出来的,就是命名函数表达式,不写的就是匿名函数表达式 例子: function aaa(){};这就是函数声明 var a=function aaa(){};命名函数表达式 var a=function(){};匿名函数表达式 下面的都是函数表达式 (function aaa(){}) ~function aaa(){} -function aaa(){}

函数声明

语法 function name([param,[, param,[..., param]]]) { [statements] } name 函数名 param 传递非函数的参数名,参数个数最多255个. statements 构成函数体的语句. 描述 通过函数声明构造的函数是Function对象,所以拥有一切Function对象所有的属性,方法和行为. 函数默认返回undefined,如果想返回其他值,函数必须使用return语句来返回你想返回的值. 通过条件语句判断创造的函数 函数可以通过条

“函数声明”、“函数原型”与“函数定义”辨析

最近在看一本关于C的书,对函数声明和函数定义的定义很是模糊,分不清楚,百度了一下,发现一篇帖子写的很是不错,转载过来: 原文: 对函数的“定义”和“声明”不是一回事.函数的定义是指对函数功能的确立,包括指定函数名,函数值类型.形参及其类型以及函数体等,它是一个完整的.独立 的函数单位.而函数的声明的作用则是把函数的名字,函数类型以及形参的类型.个数和顺序通知编译系统,以便在调用该函数时进行对照检查(例如,函数名是否 正确,实参与形参的类型和个数是否一致),它不包括函数体.————谭浩强 ,<C程

Javascript中函数声明与函数表达式的不同

定义函数的方式有两种:一种是函数声明,另一种是函数表达式. 函数声明的语法如下: 1 function functionName(arg0,arg1,arg2){ 2 //函数体 3 } 函数表达式的语法如下: 1 var functionName = function(arg0,arg1,arg2){ 2 //函数体 3 } 两者的区别: 函数声明的特征就是函数声明提升,即执行代码之前js解析器会先读取函数声明,所以如下的代码不会提示错误. 1 sayHi(); 2 function sayH

JavaScript 中对变量和函数声明的提前示例

如题所示,看下面的示例(可以使用Chrome浏览器,然后F12/或者右键,审查元素.调出开发者工具,进入控制台console输入)(使用技巧: 控制台输入时Shift+Enter可以中途代码换行) var name = "xiaoming"; (function(){ var name = name || "小张"; console.info(name); })();// 小张 (function(){ name = name || "小张";

[转]javascript函数定义表达式和函数声明的区别

在javascript中,函数有两种定义写法,函数定义表达式和函数声明,其例子分别如下所示: var test = function(x){ return x; } function test(x){ return x; } 尽管函数定义表达式和函数声明语句包含相同的函数名,并且都创建了新的函数对象,但是这二者却有区别. 函数声明语句中的函数名是一个变量名,变量指向函数对象. 函数定义表达式和通过var声明变量一样,其函数被提前到了脚本或函数的顶部,因此它在整个脚本和或函数内都是可见的.这样的话

javascript函数声明方式

javascript中函数的声明有三种方式: 最常见的函数声明: fun();//可以调用,因为这种声明方式会被浏览器优先加载. function fun() { alert("声明式的函数声明"); } 函数表达式的声明: var fun2=function() { alert("表达式的函数声明"); } fun2();//这种方式的声明,必须写在函数声明之后,因为这种声明方式不会被浏览器优先加载. 通过对象的函数声明: var fun2 = Function(