就算是非常有经验的C程序员,也对那些比简单数组/指针更复杂一些的声明感到头疼。比如说,下面这个是一个指针的数组,还是一个数组的指针?
int*a[10];
下面这货到底是什么?
int(*(*vtable)[])();
当然了,这货是一个指针,指向一个数组,这个数组的每个元素是一个指针,指向一个函数,函数的返回值类型是int :)这篇短文希望能够教会你一个非常简单地读懂复杂声明的方法。我99%肯定我在80年代读过这篇,但是不记得具体是在什么地方读到的了。我怀疑是我自己发现这个的(尽管我总会被计算机语言结构和神秘的事物搞得很兴奋)。然而我的确记得,能够写出一个程序,将任何声明转换成英语。== 黄金法则 ==这个法则是这样说的:
引用
从标识符开始(或者最内层的结构,如果不存在标识符的话,通常出现于函数指针),首先向右看,直到遇到 ) 括号或者结束,看到什么就说出来;然后向左看,直到遇到 ( 括号或者回到行首,看到什么就说出来。跳出一层括号,重复上述过程:右看看,说出来;左看看,说出来。直到你说出变量的类型或者返回值(针对函数指针),也就表示你把声明都读完了。
最简单的情况是这样的:
inti;
从 i 开始,你向右看,啥都没看到;然后就向左看,看到了int,说出来:i是一个int。然后看个复杂一点的:
int*a[3];
从 a 开始:向右看,说“是一个包含3个元素的数组”;向左看,说“数组的每个元素是指针”;向右看,啥都没;向左看,说“指针指向int”。综合起来就是: a 是一个包含3个元素的数组,每个元素是一个指针,指向int。加上一对括号让它看起来更怪异点儿:
int(*a)[3];
像在普通表达式中一样,括号改变了阅读/计算的顺序。从 a 开始:向右看,遇到括号了,往回;向左看,说“是一个指针”,遇到(括号,跳出来;向右看,[3],说“指向一个包含3个元素的数组”;向左看,int,说“数组的每个元素是int”。综合起来:a是一个指针,指向一个包含3个元素的数组,数组的每个元素是一个int。好,再来看看这个:
externint*foo();
赞,你说:foo是一个函数,返回一个指针,指向int。接下来跳一步:就像我们可以定义一个指向int的指针,我们也可以定义一个指向函数的指针。在这种情况下,不需要extern了(因为不是函数的前向引用声明),而是一个变量的定义。这是一个基本的函数指针:
int(*foo)();
从foo开始:向右看,遇到括号,往回;向左看,*,说“是一个指针”,遇到左括号,跳出来;向右看,(),说“指向一个函数”;向左看,int,说“函数返回int”。综合起来:foo是一个指针,指向一个函数,函数返回int。下面是一个数组,每个元素是一个指针,指向函数,函数返回int:
int(*Object_vtable[])();
你还需要最后一个,诡异的难以置信的声明:
int(*(*vtable)[])();
这是一个指针,指向一个数组,数组的每个元素是个指针,指向一个函数,函数的返回值是int。发现了吗?这货就是上面那个object_vtable的指针,也就是你定义的每一个对象需要的虚函数表(vtable)的指针。这个指向vtable的指针是一个vtable的地址,例如,&Truck_vtable (就是某个Truck类的实例虚函数表的指针)。== 总结 ==接下来的例子总结了所有C++为了实现多态性所建造的虚函数表需要的所有情形(就像最初的C Front - C++转C翻译器)。
int*ptr_to_int;
int*func_returning_ptr_to_int();
int(*ptr_to_func_returning_int)();
int(*array_of_ptr_to_func_returning_int[])();
int(*(*ptr_to_an_array_of_ptr_to_func_returning_int)[])();
--
转载请注明出自http://www.felix021.com/blog/read.php?2072,如是转载文则注明原出处,谢谢:)
分享到:
相关推荐
C源程序由预处理器指令、函数定义和全局声明构成。良好的编程习惯包括遵循缩进规则、合理命名变量和函数、使用注释来解释代码功能。C语言使用特定的字符集,并有一套严格的词汇规则,例如关键字、标识符和运算符。 ...
### C语言和C++在声明和定义之间的区别 在编程领域,尤其是在学习和使用C语言与C++时,理解和区分“声明”与“定义”的概念至关重要。这两种语言虽然有着密切的联系,但在处理声明和定义方面存在一些重要的差异。...
函数的定义、声明和调用是C语言编程中不可或缺的部分。本篇将深入探讨这三个概念,以及如何处理参数传递,特别是数组作为函数参数的情况。 1. **函数的定义**: 函数定义是创建一个函数的过程,它包括函数名、返回...
函数在C语言中扮演着重要角色,课件会介绍函数的定义、调用、参数传递以及函数指针,这些都是编写复杂程序的关键。同时,还会有关于递归函数的讲解,让读者了解如何利用函数自身调用来解决特定问题。 结构体和共用...
C语言风格的名字修饰简单地在标识符前加上下划线,而C++风格的名字修饰更为复杂,涉及到了参数类型和返回类型,以确保每个重载的函数或变量都有一个独特的符号。 总之,C++的函数声明和定义以及变量声明和定义是...
### C语言中的各种声明详解 #### 一、概述 C语言是一种广泛使用的程序...无论是基本类型还是复杂类型,C语言都提供了丰富的声明方式来满足不同的需求。理解这些声明方式对于编写高效、可读性强的C语言程序至关重要。
### 如何理解C和C++中的复杂类型声明 在学习C和C++的过程中,经常会遇到一些复杂的类型声明,这些声明可能会让初学者甚至有一定经验的开发者感到困惑。本文旨在逐步解析这类复杂声明,并通过一系列示例帮助读者掌握...
理解复杂的C/C++声明 const, typedef, 函数指针 在C/C++编程中,声明是一种定义变量、函数、数组、指针等的方式。 declares 是一种基本的语法结构,用于定义变量、函数、数组、指针等。在本文中,我们将详细介绍...
### 教你理解复杂的C/C++声明 在学习C或C++编程时,理解复杂的声明是必不可少的一部分。本文将从几个具体的例子出发,逐步解析如何理解这些看似难以捉摸的声明,并帮助读者建立起清晰的认知框架。 #### 基础概念...
4 优先级和结合性在C语言中,类型说明符、指针运算符、数组运算符和函数运算符的优先级和结合性是理解复杂声明的关键。类型说明符的优先级最高,接着是函数运算符,然后是数组运算符,最后是指针运算符,它们都是从...
### 教你理解复杂的C声明 对于初学者来说,理解C语言中的复杂声明是一大挑战。本文将通过解析几个典型的复杂声明案例,帮助读者更好地掌握这一技能。 #### 1. 多级指针声明 首先来看一个较为复杂的声明示例: ```...
`cdecl`不仅适用于初学者,也是经验丰富的C程序员的宝贵工具,因为它可以帮助检查和验证复杂的声明,确保它们的正确性。此外,它还能帮助开发者在遇到不常见的或者不熟悉的声明语法时快速理解其含义,从而提高编程...
理解复杂指针声明对于编写高级C程序至关重要,尤其是在处理动态内存分配、函数指针和复杂数据结构时。通过熟练掌握右左法则,开发者可以更好地解析和编写这类声明,从而提高代码的清晰度和可维护性。在实际编程中,...
.C文件通常代表源代码文件,其中包含了函数定义、变量声明以及实现的逻辑。在嵌入式C语言模板中,C-MODULE.c可能包含以下内容: 1. 头文件包含:首先,源文件会包含相关的.H头文件,确保所有必要的声明都已引入。 2...
右左法则是一种解析C语言中复杂指针声明的方法,它不是C语言标准的一部分,而是根据标准中的声明规则归纳出来的。该法则的英文原文是:“The right-left rule: Start reading the declaration from the innermost ...
结构体(Struct)和联合体(Union)是C语言中用于构建复杂数据类型的工具,文件内容中包含了结构体和联合体的定义及其使用。比如定义了一个结构体N并初始化: ```c typedef struct N { int a_s; char b_s; } N; N ...
函数是C语言的核心组成部分,它们是代码的可重用模块,允许我们将复杂的问题分解为更小、更易于管理的部分。本教程“C语言函数范例教程大全”专注于通过实例教学,帮助学习者深入理解和应用C语言中的函数。 一、...
C语言中的数组是一种重要的数据结构,它允许程序员存储和管理大量相同类型...总的来说,C语言的数组功能强大且灵活,是构建复杂程序的重要工具。熟练掌握数组的使用和注意事项对于编写高效、可靠的C语言程序至关重要。
在讨论C语言指针教学中定义复杂数据结构的作用及方法时,我们首先要明确指针的概念和其在C语言中的重要性。指针是C语言的一个核心概念,它是指向某个数据类型的地址的变量。在C语言中,指针不仅仅用于表示内存地址,...
在C语言中,声明语句是用来定义变量、函数或类型的一种语法结构,它告诉编译器变量或函数的类型和作用。...熟练掌握声明的语法对于阅读和编写C语言代码至关重要,尤其是在处理涉及函数指针和复杂数据结构的情况下。