C/C++ 函数设计基础 20130918

函数式程序的基本功能单元,是模块化程序设计的基础,即使函数的功能正确是不够的,因为函数设计的细微缺点很容易导致函数被错用。

了解函数的基本知识,堆栈和堆的相似点和不同点;函数的接口设计和内部实现,断言、const,存储类型,递归函数等等。

1.认识函数

函数分为库函数和用户自定义的函数,两者在本质上是一致的,知识前者是预编译好的。对于静态链接的函数库或者类库,如果你调用其中的函数,那么连接器慧聪相应的苦衷调去这些函数实现的源代码并且把它们连接到你的程序中。如果你没有使用库函数,则不会讲他么连接到你的程序中。如果你是用的是动态连接库(DLL),运行的时候需要将所有的DLL复制到运行环境的目录中。连接的本质就是把一个名字实现绑定到对他的每一个引用语句上面,如果你没有调用自己编写的函数,那么是不会为该函数生成任何可以执行的代码。

2.函数原型和定义

C语言中存在着函数前置声明的概念,因为在C语言中,同一个作用域中不能出现同名的全局函数,所以前置声明足矣表明一个函数定义的存在性和唯一性。

形参和实参:在函数原型或者地宫一以及catch中的参数列表中的被生命的对象,指针等等;实参就是实际调用函数的时候的参数列表。

函数调用的实际就是用实参来初始化形参而不是替换形参,在声明函数的时候,最好将参数的名称给出,虽然编译器会忽略他们,便于阅读。

3.函数调用的方式

一般函数都支持三种调用方式:像过程一样调用(表达式中调用),嵌套调用和递归调用。如果函数咩有返回值,则不能够在表达式中使用。还用一种不疆场使用的方式就是回调函数。

4.认识函数的堆栈

函数的调用必须通过堆栈来完成,函数堆栈实际上使用的是程序的堆栈段内存空间,虽然程序的堆栈是系统为程序分配的一种静态数据区,但是函数堆栈确实在被调用的时候才动态分配的。也就是说,我们不可以在编译的时候就为函数分配好一块静态空间作为堆栈。因为无法在编译的时候确定函数运行时所需要的堆栈的大小;而是函数在调用结束之后如果还保留他的堆栈空间,就会造成内存空间浪费,而且会他被耗内存,不切实际。

堆栈是自动管理的,局部变量的创建和销毁,堆栈的释放都是韩侯蔌自动完成的,不需要程序员的干涉。局部变量在程序执行刘到达它的定义的时候创建,在退处所在的程序快的时候,自动清退,将空间返还给程序。显然堆栈是在预先分配好的内存空间上创建的,不需要运行的时候在搜索,因此这样比动态内存分配空间要快而且更加安全。这就是堆栈和堆的区别。

函数堆栈的三个主要用途:在进入函数前保存环境变量和返回地址,在进入函数的时候,保存实参的拷贝。在函数体内部保存局部变量。

5.函数的调用规范

函数调用规范决定了函数调用实参压栈,退栈,堆栈释放的方式,以及函数名的改编(Naming-Mapping)的方案。

__cdecl: C/C++ 函数默认的调用规范,参数从左向右传递并且压入栈中,由调用函数负责堆栈的清退,因此这种方式方便传递个数可变的参数给被调用的函数。

__stacall: WinAPI的调用规范。参数从右向左一次传递并且压入栈中,用调用函数负责堆栈的清退。

__thiscall: C++ 非静态成员函数的默认调用规范,不可以使用个数可以变化的参数。当调用非静态函数的时候,this指针直接保存在ECX寄存器中而非压入函数的堆栈中。

__fastcall: 该规范所修饰的函数的实参将被直接传递到CPU寄存器中而不是内存的堆栈中。堆栈的清理有被调用函数清退。该规范不可以用于成员函数。

6.函数的连接规范

使用不同的编程语言,进行软件的联合开发,需要统一函数、变量、数据类型、常量等等的连接规范( Linkage Specification),特别是不同的模块之间共享的数据接口部分,当开发程序库的时候,需要明确连接规范。

对于静态链接库lib和动态链接库dll中的全局数据类型,全局函数,全局变量,他的连接规范必须在两端保持一致,否则会出现连接error,这是因为普通封装的DLL的函数库湖或者类库,客户端在创建的时候一般需要与他们的导出库(.lib)进行连接,除非使用loadLibrary和getProcAddress() 来获得dll中的函数地址。

7 函数参数传递

函数接口的两个要素:参数和返回值,在C语言中函数的参数和返回值的传递方式有两种:值传递(Pass by value)和地址传递(pass by pointer),在C++中增加了引用传递( Pass by reference).引用传递的效果和指针传递的效果相似。不论函数的原型还是定义,都需要明确写出每一个参数的名字和类型,如果参数的列表是空的,最好加上一个void,这是因为标准的C会把空的参数列表解释成可以接受任何类型和个数的参数,但是对于标准的C++则会把没有参数列表解释成不可以接受任何类型的参数。

如果参数是指针,且仅作输入用,应该在指针上面加上const,防止通过该指针修改指向内存单元的数据。如果输入的参数以值传递的方式传递对象,则易改用“const & ”方式传递,因为引用的创建和销毁不会调用对象的构造函数和析构函数可以提高效率。

8返回值得规则

函数返回值的方式有两种:使用return语句返回和使用输出参数。尤其是当函数的返回值不止一个的时候,仅仅使用return是不够的。如果没有返回值,函数声明返回值的类型是void。标准的C程序,如果不指定返回值类型,一律按照int方式处理;C++中函数必须声明返回值得类型.

9 函数内部的实现机制

不同的功能的函数,其内部实现的各不相同, 我们需要在函数体的入口处和出口处把关,也提高函数的质量.

很多的程序出错是因为非法的参数传递,所以我们应该充分理解并且正确使用断言(assert), 在return中正确性进行检查。同时return语句不可以返回指针,指针指向的内存空间是在堆栈的内存中或者是堆栈内存中的数据引用。因为这些数据会在函数结束的时候自动释放。

char * func(void){

char str[] = “hello world”;//store data in the stack,

cout << sizeof(str) << endl; // 12

cout << strlen(str) << endl; //11

return str;// str指向的单元被释放,存在风险,不是我们想要的结果

}

char * func( void){

char * str = “hello world”;// right store data in static data area

return str; //这样是可以的,但是程序没运行一次,就会创建一个

}

return String(s1+s2);

String result(s1+s2); return result;

后面这一种方式比较低效:这样会做三件事情,result对象被创建,同时调用相应的构造函数完成初始化;然后调用拷贝构造函数,把result赋值到保存返回值得外部存储单元中;最后result对象在函数结束的时候,销毁对象,调用析构函数。但是第一种方式直接创建一个临时变量并且返回,编译器可以直接把临时对象创建并且初始化,在外部存储单元中,省去了拷贝构造和析构函数的开销,提高了效率。

函数内部的static变量是用记忆的功能。

13 使用const提高函数的健壮性

const更加强大的作用就是修饰函数的返回值和参数,甚至是函数的定义体。

Const修饰的东西都是受C/C++语言实现的静态类型安全检查机制的保护,可以预防意外的修改,提高程序的健壮性。 Use const whenever you need

1)       使用const修饰参数

参数用于输出,不论他使用什么数据类型,也不论采用指针传递还是引用传递,都是不可以加上const修饰的,否则将失去输出的工呢过,const只可以修饰输入参数。如果还想保护指针本身,可以声明指针本身是常量,放置该指针的值被改变。

void OutputString( const char * const pStr);

如果采用值传递的方式传递的参数,因为是默认创建的值得拷贝,所以技术在程序中修改了参数的值,也不会影响原来程序中的值,没有必要天剑const修饰。为了提高效率可以修改参数传递的方式 为引用传递,不会产生临时变量,但是可能会修改原来的参数的值,我们只要使用const修饰即可:

void func(const int & a); 但是对于基本的参数类型好似没有构造函数和析构函数的,所以没有必要。但是对于ADT数据结构,推荐使用这种方式。

2)使用const修饰函数的返回值

如果给指针传递的韩侯蔌返回值加上const,那么函数的返回值是一种契约性常量,不能够别直接修改,并且该返回值只可以被赋值给加上const修饰的同类型的指针,除非强制性转换。

const char* getString(void);

char * str = getString();//编译出错

const char * str = getString();// right way

C++复习4.函数设计基础的更多相关文章

  1. C++复习:函数模板和类模板

    前言 C++提供了函数模板(function template).所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来代表.这个通用函数就称为函数模板.凡是函数体 ...

  2. C++复习11.函数的高级特性

    C++ 函数的高级特性 20131002 C++函数增加了重载(override), inline, const, virtual四种机制,重载和内联机制既可以用于全局函数,也可以用于类的成员函数.c ...

  3. OopenCV复习及函数深入理解(轮廓查询及绘图)

    核心函数:(后面标明号的,下面有解析) int cvFindContours(Iplimage* img,//这是输入函数,必须是8bit,单通道的图像---1 CvMemStorage* stora ...

  4. python 复习 4-1 函数、参数、返回值、递归

    函数 完成特定功能的一个语句组,这个语句组可以作为一个单位使用,并且给它组语句取一个名子,即函数名 可以通过函数名在程序不同地方多次执行,即函数调用 预定义函数(可以直接使用) 自定义函数(自编写的) ...

  5. php课程 6-24 字符串函数有哪些(复习)

    php课程 6-24 字符串函数有哪些(复习) 一.总结 一句话总结: 二.php课程 6-24 字符串函数有哪些(复习) 上次复习:--------------------------------- ...

  6. 【javascript基础】2、函数

    前言 我在上一篇[javascript基础]基本概念中介绍了javascript的一些基本概念,多谢大家的阅读和意见,自己写的东西可以被大家阅读,真心高兴,刚开始发布的时候我一直盯着阅读人数,虽然知道 ...

  7. day13(函数嵌套定义,global,nonlocal关键字,闭包,装饰器)

    一,复习 ''' 1.函数对象:函数名 => 存放的是函数的内存地址 1)函数名 - 找到的是函数的内存地址 2)函数名() - 调用函数 => 函数的返回值 eg:fn()() => ...

  8. python13 1.函数的嵌套定义 2.global、nonlocal关键字 3.闭包及闭包的运用场景 4.装饰器

    ## 复习   '''1.函数对象:函数名 => 存放的是函数的内存地址1)函数名 - 找到的是函数的内存地址2)函数名() - 调用函数 => 函数的返回值  eg:fn()() =&g ...

  9. 前端笔记之JavaScript(七)深入函数&DOM那点事

    一.函数补充 1.1 arguments类数组对象 arguments 是一个对应于传递给函数的参数的类数组对象. 在函数中,使用特殊对象 arguments,开发者无需明确指出参数名,就能访问它们. ...

随机推荐

  1. RabbitMQ、Memcache、Redis RabbitMQ

    RabbitMQ 解释RabbitMQ,就不得不提到AMQP(Advanced Message Queuing Protocol)协议. AMQP协议是一种基于网络的消息传输协议,它能够在应用或组织之 ...

  2. 『NiFi 学习之路』把握 —— 架构及主要部件

    一.概述 通过前面几篇文章的学习,相信你对 NiFi 有了一个基础性的了解. 数据处理和分发系统 是什么概念? NiFi 系统中数据的传递方式是怎样的? NiFi 的重要 Processor 有哪些? ...

  3. java中hashSet原理

    转自: http://blog.csdn.net/guoweimelon/article/details/50804799 HashSet是JavaMap类型的集合类中最常使用的,本文基于Java1. ...

  4. LigerUI ligerComboBox 下拉框 表格 多选无效

    $("#txt1").ligerComboBox({ width: 250, slide: false, selectBoxWidth: 500, selectBoxHeight: ...

  5. React组件绑定this的四种方式

    题图 By HymChu From lnstagram 用react进行开发组件时,我们需要关注一下组件内部方法this的指向,react定义组件的方式有两种,一种为函数组件,一种为类组件,类组件内部 ...

  6. LINUX SHELL 笔记 02: 变量初识

    https://www.shellscript.sh/variables1.html 变量是一个可操作(读.写)的内存块的名字. 尝试-1 创建一个变量: root@iZwz:~/labs# sh m ...

  7. 前端学习笔记之BOM和DOM

    前言 到目前为止,我们已经学过了JavaScript的一些简单的语法.但是这些简单的语法,并没有和浏览器有任何交互. 也就是我们还不能制作一些我们经常看到的网页的一些交互,我们需要继续学习BOM和DO ...

  8. 树梅派配置ad-hoc网络

    树梅派配置ad-hoc网络 更新与安装 1.更改源/etc/apt/source.list: http://mirrors.tuna.tsinghua.edu.cn/raspbian/raspbian ...

  9. linux安装coreseek

    coreseek就是一个中文词库加上sphinx组合而成的. 1.下载coreseek 下载到/usr/local/src目录文件下 wget  http://www.coreseek.cn/uplo ...

  10. Why not inherit from List<T>?

    问题: When planning out my programs, I often start with a chain of thought like so: A football team is ...