| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 962 人关注过本帖
标题:[原创]宏定义、const与内联函数的简单介绍
取消只看楼主 加入收藏
BugEyes
Rank: 1
等 级:新手上路
帖 子:37
专家分:0
注 册:2006-1-10
收藏
 问题点数:0 回复次数:1 
[原创]宏定义、const与内联函数的简单介绍

原始url:
http://www.blog.edu.cn/user1/20989/archives/2006/1163814.shtml

1.宏定义

宏定义命令用来将一个标识符定义为一个字符串,该标识符被称为宏名,被定义的字符串称为替换文本。宏定义可以分为两类:简单宏定义和带参数的宏定义。

1.1简单宏定义
这种宏定义在C/C++中处处可见,形式如#define N 5。简单来说,就是用N来代替5,在后面的程序代码中,凡是出现N的位置均可直接替换为5。要注意的是,宏只是简单地替换,并没有类型的概念。

另外,我们也经常可以看到类似#define N的写法,定义了名字为N的宏,却什么也不表示,这时候往往有特殊用法。我在前面的“关于文件包含”中曾经提到过,可以用来防止文件的重复包含。见http://bugeyes.blog.edu.cn/user1/20989/archives/2005/191285.shtml

1.2带参数的宏定义
带参数的宏定义可以接受参数,然后带入参数后展开宏,这样,程序中对带参数宏的替换后可能会是一个表达式。举例如下:

#i nclude <iostream.h>
#pragma hdrstop
#define CircleArea(x) 3.14*x*x
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char* argv[])
{
cout<<"Please input the radius:"<<endl;
double r;
cin>>r;
cout<<"The Area is:"<<CircleArea(r);
getchar();
getchar();
return 0;
}
//---------------------------------------------------------------------------
在上面的代码中,CircleArea(r)将会被替换为3.14*r*r这样一个表达式。同样,我们也可以写一个类似的函数来实现同样功能,但是调用函数时要保存现场、恢复现场,增加了程序的运行时间和占用的空间。而带参数的宏定义不存在现场的问题,只是会增加程序代码的长度,基本不会增加运行时间。
但是,使用带参数的宏定义时,要注意避免表达式参数带来的影响。如上面的程序修改成下面的样子:
#i nclude <iostream.h>
#pragma hdrstop
#define Product(x) x*x
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char* argv[])
{
cout<<"Please input two digit:"<<endl;
double m,n;
cin>>m>>n;
cout<<"The product is:"<<Product(m+n);
getchar();
getchar();
return 0;
}
//---------------------------------------------------------------------------
运行结果为:
Please input two digit:
3 2
The product is:11
结果并不像我们想象的那样为5*5=25,原因就在于宏定义的“直接替换”。对于这样的需要,我们往往把程序写成下面的样子:
#i nclude <iostream.h>
#pragma hdrstop
#define Product(x) (x)*(x)
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char* argv[])
{
cout<<"Please input two digit:"<<endl;
double m,n;
cin>>m>>n;
cout<<"The product is:"<<Product(m+n);
getchar();
getchar();
return 0;}
//---------------------------------------------------------------------------
此时,运行结果为:
Please input two digit:
3 2
The product is:25
再例如下面的程序:
#i nclude <iostream.h>
#pragma hdrstop
#define Product(x) x*x
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char* argv[])
{
cout<<"Please input two digit:"<<endl;
double m;
cin>>m;
cout<<"The product is:"<<Product(m++)<<endl;
cout<<"m="<<m<<endl;
getchar();
getchar();
return 0;
}
//---------------------------------------------------------------------------
与我们想象的不一样,运行结果为:
Please input two digit:
3
The product is:12
m=5
其原因也在于宏定义的“直接替换”,虽然我们很少这样做(指用m++表达式作参数),但确实宏定义在有些时候要谨慎使用。为了保证使用m++表达式作为参数时只执行++运算一次,可以用函数来实现:
#i nclude <iostream.h>
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
double fun(double x)
{
return x*x;
}

int main(int argc, char* argv[])
{
cout<<"Please input a digit:"<<endl;
double m;
cin>>m;
cout<<"The product is:"<<fun(m++)<<endl;
cout<<"m="<<m<<endl;
getchar();
getchar();
return 0;
}
//---------------------------------------------------------------------------

运行结果为:
Please input a digit:
3
The product is:9
m=4
2. 带类型的常数定义(const关键字)
类似于#define,使用const关键字也可以定义常数。两者区别在于const定义的常数有类型,而#define只是简单定义字符序列。如const int a=5;则定义了整数类型常数a且值为5。但是在使用const修饰指针变量时,仍要注意其位置的不同。
2.1 const在类型前面
const int *p;表示指针变量所指的内存空间中的值不允许修改。如下面的代码在编译时将会提示错误“Cannot modify a const object

”。
#i nclude <iostream.h>
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char* argv[])
{
int a=5;
const int *p=&a;
*p=3;//错误写法
cout<<*p;
getchar();
return 0;}
//---------------------------------------------------------------------------
当然,此时仍可以通过变量a来修改内存空间的值,只是不能通过*p来修改。这时,尽管不能通过*p来修改对应空间的值,但是却可以修改

指针变量p使其指向另外的内存空间。如:
#i nclude <iostream.h>
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char* argv[])
{
int a=5;
const int *p=&a;
int b=7;
p=&b;
cout<<*p;
getchar();
return 0;}
//---------------------------------------------------------------------------
上面这段代码可以正常执行,并输出变量b的值7。
2.2 const在类型后面
int const *p;表示不允许修改指针变量p的指向,但可以修改p所指内存空间的值。如下面的代码将会提示错误“Cannot modify a const

object”。
#i nclude <iostream.h>
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char* argv[])
{
int a=5;
int * const p=&a;
int b=7;
p=&b;//错误写法
cout<<*p;
getchar();
return 0;}
//---------------------------------------------------------------------------
但是下面的代码却可以正常执行:
#i nclude <iostream.h>
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char* argv[])
{
int a=5;
int * const p=&a;
*p=3;
cout<<*p;
getchar();
return 0;}
//---------------------------------------------------------------------------
2.3 一点补充
一个类型为T的对象能够用于使用const从T派生的类型的对象可以使用的场合,反之不成立。即:
int x,*px;
const int y,*py;
py=&x;//正确
px=&y;//错误
另外,const经常用在函数的参数声明中,尤其是指针参数,以说明在子函数中不能修改指针参数所指内容。如void fun(const int *p,...)这样的函数定义中,不能修改p所指空间的内容。
3.内联函数
内联函数使用inline来修饰,内联函数的函数体直接在其调用位置展开,而不用保存和恢复现场,这一点与带参数的宏定义非常相似,当函数体代码较短而函数多次被调用的情况,可以大幅度提高效率。如下定义:
#i nclude <iostream.h>
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
double inline fun(double x)//或可写作inline double fun(double x)
{
return x*x;
}
int main(int argc, char* argv[])
{
cout<<"Please input a digit:"<<endl;
double m;
cin>>m;
cout<<"The product is:"<<fun(m++)<<endl;
cout<<"m="<<m<<endl;
getchar();
getchar();
return 0;
}
//---------------------------------------------------------------------------
内联函数的执行过程与带参数宏定义很相似,但参数的处理不同。带参数的宏定义并不对参数进行运算,而是直接替换;内联函数首先是函数,这就意味着函数的很多性质都适用于内联函数,即内联函数先把参数表达式进行运算求值,然后把表达式的值传递给形式参数。
内联函数与带参数宏定义的另一个区别是,内联函数的参数类型和返回值类型在声明中都有明确的指定;而带参数宏定义的参数没有类型的概念,只有在宏展开以后,才由编译器检查语法,这就存在很多的安全隐患。
使用内联函数时,应注意以下问题:
1)内联函数的定义性声明应该出现在对该函数的第一次调用之前。
2)内联函数首先是函数,函数的很多性质都适用于内联函数,如内联函数可以重载。
3)在内联函数中不允许使用循环语句和switch结果,带有异常接口声明的函数也不能声明为内联函数。

搜索更多相关主题的帖子: 定义 内联 const blog 函数 
2006-03-13 12:42
BugEyes
Rank: 1
等 级:新手上路
帖 子:37
专家分:0
注 册:2006-1-10
收藏
得分:0 
#pragma hdrstop表示预编译头文件到此为止,后面的头文件不进行预编译。BCB可以预编译头文件以加快链接的速度,但如果所有头文件都进行预编译又可能占太多磁盘空间,所以使用这个选项排除一些头文件。
有时单元之间有依赖关系,比如单元A依赖单元B,所以单元B要先于单元A编译。你可以用#pragma startup指定编译优先级,如果使用了#pragma package(smart_init) ,BCB就会根据优先级的大小先后编译。
相关资料请见:
http://bugeyes.blog.edu.cn/user1/20989/archives/2006/1163999.shtml

学前班校长,个人blog:http://bugeyes.blog.
2006-03-13 23:05
快速回复:[原创]宏定义、const与内联函数的简单介绍
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.016121 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved