zoukankan      html  css  js  c++  java
  • C++/C学习笔记(二)

    1.函数原型和定义

    函数原型的格式:

    [作用域][函数的连接规范]返回值类型[函数的调用范围]函数名(类型1[形参名1],类型2[形参名2],...);

    形参:在函数原型或定义及catch语句的参数列表中被声明的对象或指针、宏定义中的参数、模版定义中的类型参数等。

    实参:函数调用语句中以逗号分隔的参数列表中的表达式、宏调用语句中以逗号分隔的列表中一个或多个预处理标识符的序列、throw语句的操作数、表达式的操作数、模版实例化时的实际类型参数等。

    函数调用中参数传递的本质就是用实参来初始化形参而不是替换形参。

    2.函数调用

    一般函数支持3种调用方式:像过程一样调用,嵌套调用,递归调用。若函数没有返回值,则不能在表达式中调用。

    不常用的调用方式:回调函数,往往是具体应用领域相关的实现,而API函数则是应用无关的通用功能的实现。

    常用的注册回调函数的系统函数:set_new_handler(),atexit(),set_termi

    nate(),beginthread(),set_unexpected(),signal()等。

    3.函数堆栈

    函数堆栈实际上使用的是程序的堆栈段内存空间,虽然程序的堆栈段是系统为程序分配的一种静态数据区,但函数堆栈却是在调用到它的时候才动态分配。

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

    设m_ch1='a';m_ch2='b';m_int=0;

    C++输出一般类型对象地址:

    count<<"Address of m_int:"<<test.GetIntAddr()<<endl;

    C++输出字符串地址:

    printf("Address of m_ch1:%p\n,&(test.m_ch1));

    count<<"Address of m_ch2:"<<(void*)test.Getchar2Addr()<<endl;

    4.函数调用规范:

    决定了函数调用的实参压栈,退栈,及堆栈释放的方法,以及函数名改编的方案。Windows环境下常用的调用规范有:

    _cdecl:C/C++函数的默认调用规范,参数从右向左依次传递并压人堆栈,由调用函数负责堆栈的清退,利于传递个数可变的参数给被调函数。

    _stdcall:Win API函数使用的调用规范。参数从右向左依次传递并压人堆栈,由被调用函数负责堆栈的清退。

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

    _fastcall:该规范所修饰的函数的实参将被直接传递到CPU寄存器中而不是内存堆栈中。堆栈清退由被调用函数负责,该规范不能用于成员函数。

    函数必须指定一个调用规范,特别是在模块之间的逻辑接口中,每一个函数原型的调用规范必须与其实现的调用规范保持一致,否则会出现编译连接错误。若调用了在某个DLL中实现的COM对象的方法,而这些方法在创建时却没有显示地指定调用规范,那么它们会使用环境默认的调用规范,而若此时程序使用的调用规范与默认的不一致,虽然程序可以通过编译和链接,但运行时就可能崩溃。

    5.函数连接规范

    对COM接口及其使用的数据类型来说,是否采用统一的连接规范,对其二进制兼容性和可移植性都无影响。

    但是对于定义普通静态链接库(.Lib)和动态链接库(.DLL)中的全局数据类型、全局函数、全局变量、甚至全局常量,它们的连接规范必须在两端(库和调用端)保持一致,否则客户程序会出现连接问题(linking error:unresolved external symbol等),这是因为普通的封装为DLL的函数库或者类库,客户程序在创建时一般都需要与它们的导出库(.Lib)进行连接,除非使用LoadLibrary()和GetProcAddress()函数对来获得DLL中的函数。

    通用的连接规范:extern "C" 。例如:extern "C"  struct Student{...};

    6.参数传递规则

    (1)参数命名要恰当,能望文生义,输入参数和输出参数的顺序要合理,一般输出参数放在前面,输入参数放在后面,不要输入输出交叉出现。

    例如:void StringCopy(char *strDestination,char *strsource);

    (2)如果参数是指针,且仅作输入用,则应在类型前加const,以防止该指针指向的内存单元在函数体内无意中被修改。

    例如:void StringCopy(char *strDestination,const char *strsource);

    如果输入参数以值传递的方式传递对象,则宜改用"const &"方式来传递。

    (3)尽量避免函数有太多的参数,如果参数太多,在使用时可将这些参数封装为一个对象并采用地址传递或引用传递方式。

    7.返回值的规则

    函数返回值两种途径:使用return语句和使用输出参数。

    (1)不要省略返回值的类型。如果函数没有返回值,则声明为void类型。

    (2)建议正常值用输出参数获得,而错误标志用return返回。

    (3)Return语句不可返回指向“堆栈内存”的“指针”或者“引用”。

    (4)若函数返回值是一个对象,要考虑return 语句的效率:

    例如:String result(s1+s2);

          Return result;

        代码做三件事情:创建result对象同时调用相应的构造函数完成初始化;调用拷贝构造函数把result拷贝到保存返回值的外部存储单元中;result在函数结束调用析构函数时被销毁。

    而 Return String(s1+s2); 

    临时对象的构造函数语法, 编译器直接把临时对象创建并初始化在外部存储单元中,省去了拷贝和析构的开销,提高了效率。

  • 相关阅读:
    git线上操作
    IDEA快捷方式
    Java 四种线程池
    java 获取当前天之后或之前7天日期
    如何理解AWS 网络,如何创建一个多层安全网络架构
    申请 Let's Encrypt 通配符 HTTPS 证书
    GCE 部署 ELK 7.1可视化分析 nginx
    使用 bash 脚本把 AWS EC2 数据备份到 S3
    使用 bash 脚本把 GCE 的数据备份到 GCS
    nginx 配置 https 并强制跳转(lnmp一键安装包)
  • 原文地址:https://www.cnblogs.com/yingying0907/p/2618423.html
Copyright © 2011-2022 走看看