简单讲解C++的内部和外部函数以及宏的定义

C++内部函数和外部函数
函数本质上是全局的,因为一个函数要被另外的函数调用,但是,也可以指定函数只能被本文件调用,而不能被其他文件调用。根据函数能否被其他源文件调用,将函数区分为内部函数和外部函数。
内部函数

如果一个函数只能被本文件中其他函数所调用,它称为内部函数。在定义内部函数时,在函数名和函数类型的前面加static。函数首部的一般格式为:

  static 类型标识符 函数名(形参表);

  static int fun(int a, int b);

内部函数又称静态(static)函数。使用内部函数,可以使函数只局限于所在文件。如果在不同的文件中有同名的内部函数,互不干扰。通常把只能由同一文件使用的函数和外部变量放在一个文件中,在它们前面都冠以static使之局部化,其他文件不能引用。
外部函数

在定义函数时,如果在函数首部的最左端冠以关键字extern,则表示此函数是外部函数,可供其他文件调用。如函数首部可以写为:

  extern int fun (int a, int b);

这样,函数fun就可以为其他文件调用。如果在定义函数时省略extern,则默认为外部函数。本教程前面所用的函数都是外部函数。

在需要调用此函数的文件中,用extern声明所用的函数是外部函数。

【例】输入两个整数,要求输出其中的大者,用外部函数实现。

/*******file1.cpp(文件1)*******/
#include <iostream>
using namespace std;
int main( )
{
  extern int max(int,int); //声明在本函数中将要调用在其他文件中定义的max函数
  int a,b;
  cin>>a>>b;
  cout<<max(a,b)<<endl;
  return 0;
}
/*******file2.cpp(文件2)*******/
int max(int x,int y)
{
  int z;
  z=x>y?x:y;
  return z;
}

运行情况如下:

7 -34
7

在计算机上运行一个含多文件的程序时,需要建立一个项目文件(project file),在该项目文件中包含程序的各个文件。详细情况请查看:VC6.0使用教程。

通过此例可知:使用extern声明就能够在一个文件中调用其他文件中定义的函数,或者说把该函数的作用域扩展到本文件。extern声明的形式就是在函数原型基础上加关键字extern。由于函数在本质上是外部的,在程序中经常要调用其他文件中的外部函数,为方便编程,C++允许在声明函数时省写extern。例4.15程序main函数中的函数声明可写成:

  int max(int, int);

这就是我们多次用过的函数原型。由此可以进一步理解函数原型的作用。用函数原型能够把函数的作用域扩展到定义该函数的文件之外(不必使用extern)。只要在使用该函数的每一个文件中包含该函数的函数原型即可。函数原型通知编译系统:该函数在本文件中稍后定义,或在另一文件中定义。

利用函数原型扩展函数作用域最常见的例子是#include命令的应用。在#include命令所指定的头文件中包含有调用库函数时所需的信息。例如,在程序中需要调用sin函数,但三角函数并不是由用户在本文件中定义的,而是存放在数学函数库中的。按以上的介绍,必须在本文件中写出sin函数的原型,否则无法调用sin函数。sin函数的原型是:

  double sin(double x);

本来应该由程序设计者在调用库函数时先从手册中查出所用的库函数的原型,并在程序中一一写出来,但这显然是麻烦而困难的。为减少程序设计者的困难,在头文件cmath中包括了所有数学函数的原型和其他有关信息,用户只需用以下#include命令:

  #include <cmath>

即可。这时,在该文件中就能合法地调用各数学库函数了。

C++宏定义#define
可以用#define命令将一个指定的标识符(即宏名)来代表一个字符串。定义宏的作用一般是用一个短的名字代表一个长的字符串。它的一般形式为:

  #define 标识符 字符串

这就是已经介绍过的定义符号常量。如:

  #define PI 3.1415926

还可以用#define命令定义带参数的宏定义。其定义的一般形式为:

  #define 宏名(参数表) 字符串

如:

  #define S(a, b) a*b //定义宏S(矩形面积),a、b为宏的参数

使用的形式如下:

  area=S(3, 2);

用3、2分别代替宏定义中的形式参数a和b,即用3*2代替S(3, 2)。因此赋值语句展开为:

  area=3*2;

由于C++增加了内置函数(inline),比用带参数的宏定义更方便,因此在C++中基本上已不再用#define命令定义宏了,主要用于条件编译中。

(0)

相关推荐

  • C/C++宏定义的可变参数详细解析

    编写代码的过程中,经常会输出一些调试信息到屏幕上,一般会调用printf这类的函数.但是当调试解决之后,我们需要手工将这些地方删除或者注释掉.最近在看<Linux C编程一站式学习>这本书,就想到一个方法: 复制代码 代码如下: void myprintf(char* fmt, ...){}#ifdef DEBUG#define printf(fmt, args...) myprintf(fmt, ##args)#endif 调试阶段带着DEBUG调试,正式上线就可以把printf变成一个空函

  • 在C++中自定义宏的简单方法

    可以使用宏定义没有返回值的"函数".例如: 复制代码 代码如下: #define PrintMax(a, b) \   do \   { \     int x = a, y = b; \     printf("Max: %d\n", x > y ? x : y);\   } while (0) // ... PrintMax(3, 4); 这样的"函数"与真正意义上的函数有本质的区别,因为宏是一个编译前行为,仅仅是编译前对文本进行替换.

  • c++ 编程 几个有用的宏详解

    1. 打印错误信息 如果程序的执行必须要求某个宏被定义,在检查到宏没有被定义是可以使用#error,#warning打印错误(警告)信息,如: #ifndef __unix__ #error "This section will only work on UNIX systems" #endif 只有__unix__宏被定义,程序才能被正常编译. 2. 方便调试 __FILE, __LINE, __FUNCTION是由编译器预定义的宏,其分别代表当前代码所在的文件名,行号,以及函数名.

  • C++十六进制宏的用法详解

    流行的用法:用二进制的每一位代表一种状态. 001,010,100这样就表示三种状态. 通过或|运算就可以组合各种状态. 001|010=011 001|010|100=111 通过与&运算可以去除某种状态. 111&001=110 可以定义这样的宏组合成函数的参数 #defineP10x001L//001 #defineP20x002L//010 #defineP30x004L//100 voidFunc(long){} Func(P1|P2); 可以这样判断某位是否是1 由于001与x

  • C/C++ 宏详细解析

    众多C++书籍都忠告我们C语言宏是万恶之首,但事情总不如我们想象的那么坏,就如同goto一样.宏有一个很大的作用,就是自动为我们产生代码.如果说模板可以为我们产生各种型别的代码(型别替换),那么宏其实可以为我们在符号上产生新的代码(即符号替换.增加). 关于宏的一些语法问题,可以在google上找到.相信我,你对于宏的了解绝对没你想象的那么多.如果你还不知道#和##,也不知道prescan,那么你肯定对宏的了解不够. 我稍微讲解下宏的一些语法问题(说语法问题似乎不妥,macro只与preproc

  • C++中宏的使用问题详解

    宏不遵循C++中关于范围和类型的规则.这经常导致一些微妙的或不那么微妙的问题.因此,C++提供更适合其他的C++(译注:原文为the rest of C++,当指C++除了兼容C 以外的部分)的替代品,例如内联函数.模板与名字空间. 考虑一下: #include "someheader.h" struct S { int alpha; int beta; }; 如果某人(不明智地)地写了一个叫"alpha"或"beta"的宏,那么它将不会被编译,

  • 简单讲解C++的内部和外部函数以及宏的定义

    C++内部函数和外部函数 函数本质上是全局的,因为一个函数要被另外的函数调用,但是,也可以指定函数只能被本文件调用,而不能被其他文件调用.根据函数能否被其他源文件调用,将函数区分为内部函数和外部函数. 内部函数 如果一个函数只能被本文件中其他函数所调用,它称为内部函数.在定义内部函数时,在函数名和函数类型的前面加static.函数首部的一般格式为: static 类型标识符 函数名(形参表); 如 static int fun(int a, int b); 内部函数又称静态(static)函数.

  • python 函数内部修改外部变量的方法

    如果内部修改外部变量需要nonlocal,global def f1(): print("in f1..") num=111 def f2(): nonlocal num num=222 print(num) f2() print(num) f1() 以上这篇python 函数内部修改外部变量的方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们.

  • C++简单又轻松的讲解类和对象中友元函数

    目录 友元 浅解概念 友元目的 友元的三种实现 全局函数做友元 类做友元 成员函数做友元 注意事项 总结 友元 用到关键字 friend 浅解概念 举一个非常实际的例子,假如端午节到了你煮了两种粽子,一种是普通的糯米粽子,一种是特殊的五花肉粽子,糯米粽只要是客人都可以品尝,而五花肉棕只限好朋友品尝,这时候就可以用到友元的知识了.在程序里,有些私有属性也想让类外特殊的一些函数或者类访问,就要用到友元函数. 友元目的 让一个函数或者类,访问另一个类的私有属性 友元的三种实现 全局函数.成员函数.类都

  • C语言全方位讲解指针与地址和数组函数堆空间的关系

    目录 一.一种特殊的变量-指针 二.深入理解指针与地址 三.指针与数组(上) 四.指针与数组(下) 五.指针与函数 六.指针与堆空间 七.指针专题经典问题剖析 一.一种特殊的变量-指针 指针是C语言中的变量 因为是变量,所以用于保存具体值 特殊之处,指针保存的值是内存中的地址 内存地址是什么? 内存是计算机中的存储部件,每个存储单元有固定唯一的编号 内存中存储单元的编号即内存地址 需要弄清楚的事实 程序中的一切元素都存在于内存中,因此,可通过内存地址访问程序元素. 内存示例 获取地址 C语言中通

  • 简单讲解c++ vector

    在c++中,vector是一个十分有用的容器. 作用:它能够像容器一样存放各种类型的对象,简单地说,vector是一个能够存放任意类型的动态数组,能够增加和压缩数据. vector在C++标准模板库中的部分内容,它是一个多功能的,能够操作多种数据结构和算法的模板类和函数库. 特别注意: 使用vector需要注意以下几点: 1.加入头文件 <vector> 2.如果你要表示的向量长度较长(需要为向量内部保存很多数),容易导致内存泄漏,而且效率会很低: 3.Vector作为函数的参数或者返回值时,

  • 运用示例简单讲解C#取消令牌CancellationTokenSource

    目录 前言 简单示例 基础操作 定时取消 关联取消 判断取消 源码探究 构造入手 小插曲WaitHandle 注册操作 取消操作 Cancel操作 CancelAfter操作 总结 前言 相信大家在使用C#进行开发的时候,特别是使用异步的场景,多多少少会接触到CancellationTokenSource.看名字就知道它和取消异步任务相关的,而且一看便知大名鼎鼎的CancellationToken就是它生产出来的.不看不知道,一看吓一跳.它在取消异步任务.异步通知等方面效果还是不错的,不仅好用而

  • Vue2.x响应式简单讲解及示例

    一.回顾Vue响应式用法 ​ vue响应式,我们都很熟悉了.当我们修改vue中data对象中的属性时,页面中引用该属性的地方就会发生相应的改变.避免了我们再去操作dom,进行数据绑定. 二.Vue响应式实现分析 对于vue的响应式原理,官网上给了出文字描述 https://cn.vuejs.org/v2/guide/reactivity.html . vue内部主要是通过数据劫持和观察者模式实现的 数据劫持: vue2.x内部使用Object.defineProperty https://dev

  • javascript嵌套函数和在函数内调用外部函数的区别分析

    我们都知道在函数中定义的局部变量在声明他的函数体以及其嵌套的函数内始终是有定义的,并且在函数的作用域链上始终会有个对象指向全局对象,使函数能够访问到全局变量. var ga = 'global'; var func = function() { var la = 'local'; return function() { return function() { return function() { alert(la);alert(ga); } } } } a = func(); a()()();

  • Android 8.0 读取内部和外部存储以及外置SDcard的方法

    最近碰到询问我这个读取SDcard的问题, 很久没有看这部分了,所以大致看了一下, 顺便记录一下.在Android 8.0上做了测试. 一般的Android App能读取的存储空间主要有三种: app自己的私有目录,也就是/data/data/<app 目录>. 读写这个目录不需要单独的权限.每个app只能读写自己的目录,而不能读写其他app的目录. Android通过Seandroid对权限进行了管理. /sdcard. 这个其实是Android手机的internal storage. 也就

  • 简单讲解java中throws与throw的区别

    Java中throws和throw的区别讲解 当然,你需要明白异常在Java中式以一个对象来看待. 并且所有系统定义的编译和运行异常都可以由系统自动抛出,称为标准异常,但是一般情况下Java 强烈地要求应用程序进行完整的异常处理,给用户友好的提示,或者修正后使程序继续执行. 直接进入正题哈: 1.用户程序自定义的异常和应用程序特定的异常,必须借助于 throws 和 throw 语句来定义抛出异常. 1.1   throw是语句抛出一个异常. 语法:throw (异常对象);         

随机推荐