C语言中的#define是什么意思,有什么作用,怎样用??#define 定义一个标识符来表示一个常量 。
其特点是定义的标识符不占内存,只是一个临时的符号,预编译后这个符号就不存在了 。
用 #define 定义标识符的一般形式为:
#define标识符常量//注意, 最后没有分号
【define函数块c语言 c语言中define简单使用实例】#define 和 #include 一样,也是以“#”开头的 。凡是以“#”开头的均为预处理指令,#define也不例外 。
扩展资料:
宏定义 #define 一般都写在函数外面,与 #include 写在一起 。当然,写在函数里面也没有语法错误,但通常不那么写 。#define 的作用域为自 #define 那一行起到源程序结束 。如果要终止其作用域可以使用 #undef 命令 。
使用宏定义可以用宏代替一个在程序中经常使用的常量 。注意,是“经常”使用的 。这样,当需要改变这个常量的值时,就不需要对整个程序一个一个进行修改,只需修改宏定义中的常量即可 。
且当常量比较长时,使用宏就可以用较短的有意义的标识符来代替它 , 这样编程的时候就会更方便,不容易出错 。因此 , 宏定义的优点就是方便和易于维护 。
c语言中define的用法C语言是计算机软件领域非常经典的编程语言,unix、linux等众多操作系统均是由C语言编写而成 。而在硬件控制、底层驱动等应用领域,C语言更是具有不可替代的作用 。下面我就跟你们详细介绍下c语言中define的用法,希望对你们有用 。
c语言中define的用法如下:
#define是C语言中提供的宏定义命令,其主要目的是为程序员在编程时提供一定的方便 , 并能在一定程度上提高程序的运行效率,但学生在学习时往往不能 理解该命令的本质 , 总是在此处产生一些困惑,在编程时误用该命令,使得程序的运行与预期的目的不一致,或者在读别人写的程序时 , 把运行结果理解错误,这对 C语言的学习很不利 。
1. #define命令剖析
1.1 #define的概念
#define命令是C语言中的一个宏定义命令,它用来将一个标识符定义为一个字符串,该标识符被称为宏名,被定义的字符串称为替换文本 。
该命令有两种格式:一种是简单的宏定义,另一种是带参数的宏定义 。
(1)简单的宏定义:
#define宏名字符串
例:#define PI 3.1415926
(2) 带参数的宏定义
#define宏名 (参数表)宏体
例: #defineA(x) x
一个标识符被宏定义后,该标识符便是一个宏名 。这时,在程序中出现的是宏名,在该程序被编译前,先将宏名用被定义的字符串替换,这称为宏替换 , 替换后才进行编译,宏替换是简单的替换 。
1.2 宏替换发生的时机
为了能够真正理解#define的作用,让我们来了解一下对C语言源程序的处理过程 。当我们在一个集成的开发环境如Turbo C中将编写好的源程序进行编译时,实际经过了预处理、编译、汇编和连接几个过程,见图1 。
源程序预处理器修改后的源程序编译器汇编程序汇编器可重定位的目标程序连接器可执行的目标程序图1 C语言的编译过程
其中预处理器产生编译器的输出 , 它实现以下的功能:
(1)文件包含
可以把源程序中的#include 扩展为文件正文,即把包含的.h文件找到并展开到#include 所在处 。
(2)条件编译
预处理器根据#if和#ifdef等编译命令及其后的条件,将源程序中的某部分包含进来或排除在外,通常把排除在外的语句转换成空行 。
(3)宏展开
预处理器将源程序文件中出现的对宏的引用展开成相应的宏 定义,即本文所说的#define的功能 , 由预处理器来完成 。
经过预处理器处理的源程序与之前的源程序有所有不同 , 在这个阶段所进行的工作只是纯粹的替换与展开,没有任何计算功能,所以在学习#define命令时只要能真正理解这一点,这样才不会对此命令引起误解并误用 。
2 #define使用中的常见问题解析
2.1 简单宏定义使用中出现的问题
在简单宏定义的使用中,当替换文本所表示的字符串为一个表达式时 , 容易引起误解和误用 。如下例:
例1#defineN2 2
void main()
{
inta=N*N;
printf(“%d”,a);
}
(1) 出现问题:在此程序中存在着宏定义命令,宏N代表的字符串是2 2,在程序中有对宏N的使用,一般同学在读该程序时,容易产生的问题是先求解N为2+2=4,然后在程序中计算a时使用乘法,即N*N=4*4=16,其实该题的结果为8,为什么结果有这么大的偏差?
(2)问题解析:如1节所述,宏展开是在预处理阶段完成的,这个阶段把替换文本只是看作一个字符串,并不会有任何的计算发生,在展开时是在宏N出现的地方 只是简单地使用串2+2来代替N,并不会增添任何的符号,所以对该程序展开后的结果是a=2 2*2 2,计算后=8,这就是宏替换的实质,如何写程序才 能完成结果为16的运算呢?
(3)解决办法:将宏定义写成如下形式
#defineN(2 2)
这样就可替换成(2 2)*(2 2)=16
2.2 带参数的宏定义出现的问题
在带参数的宏定义的使用中 , 极易引起误解 。例如我们需要做个宏替换能求任何数的平方 , 这就需要使用参数,以便在程序中用实际参数来替换宏定义中的参数 。一般学生容易写成如下形式:
#definearea(x)x*x
这在使用中是很容易出现问题的,看如下的程序
void main()
{
inty=area(2 2);
printf(“%d”,y);
}
按理说给的参数是2 2,所得的结果应该为4*4=16,但是错了 , 因为该程序的实际结果为8,仍然是没能遵循纯粹的简单替换的规则,又是先计算再替换 了,在这道程序里,2 2即为area宏中的参数,应该由它来替换宏定义中的x,即替换成2 2*2 2=8了 。那如果遵循(1)中的解决办法,把2 2 括起来,即把宏体中的x括起来,是否可以呢?#definearea(x) (x)*(x),对于area(2 2),替换为(2 2)*(2 2)=16,可以解决,但是对于area(2 2)/area(2 2)又会怎么样 呢,有的学生一看到这道题马上给出结果,因为分子分母一样,又错了,还是忘了遵循先替换再计算的规则了,这道题替换后会变为 (2 2)*(2 2)/(2 2)*(2 2)即4*4/4*4按照乘除运算规则,结果为16/4*4=4*4=16,那应该怎么呢?解决方法是在整个 宏体上再加一个括号,即#definearea(x) ((x)*(x)),不要觉得这没必要,没有它,是不行的 。
要想能够真正使用好宏定义,那么在读别人的程序时,一定要记住先将程序中对宏的使用全部替换成它所代表的字符串,不要自作主张地添加任何其他符号,完全展 开后再进行相应的计算,就不会写错运行结果 。如果是自己编程使用宏替换,则在使用简单宏定义时 , 当字符串中不只一个符号时,加上括号表现出优先级,如果是 带参数的宏定义,则要给宏体中的每个参数加上括号,并在整个宏体上再加一个括号 。看到这里,不禁要问,用宏定义这么麻烦,这么容易出错,可不可以摒弃它,那让我们来看一下在C语言中用宏定义的好处吧 。
3宏定义的优点
(1)方便程序的修改
使用简单宏定义可用宏代替一个在程序中经常使用的常量,这样在将该常量改变时,不用对整个程序进行修改,只修改宏定义的字符串即可,而且当常量比较长时,我们可以用较短的有意义的标识符来写程序 , 这样更方便一些 。我们所说的常量改变不是在程序运行期间改变,而是在编程期间的修改,举一个大家比较熟悉的例 子,圆周率π是在数学上常用的一个值,有时我们会用3.14来表示,有时也会用3.1415926等,这要看计算所需要的精度 , 如果我们编制的一个程序中 要多次使用它 , 那么需要确定一个数值,在本次运行中不改变,但也许后来发现程序所表现的精度有变化,需要改变它的值,这就需要修改程序中所有的相关数值,这会给我们带来一定的不便,但如果使用宏定义,使用一个标识符来代替,则在修改时只修改宏定义即可,还可以减少输入 3.1415926这样长的数值多次的情况,我们可以如此定义 #definepi3.1415926,既减少了输入又便于修改,何乐而不为呢?
(2) 提高程序的运行效率
使用带参数的宏定义可完成函数调用的功能,又能减少系统开 销,提高运行效率 。正如C语言中所讲,函数的使用可以使程序更加模块化,便于组织,而且可重复利用,但在发生函数调用时,需要保留调用函数的现?。员阕?函数执行结束后能返回继续执行 , 同样在子函数执行完后要恢复调用函数的现场 , 这都需要一定的时间,如果子函数执行的操作比较多,这种转换时间开销可以忽 略,但如果子函数完成的功能比较少,甚至于只完成一点操作,如一个乘法语句的操作,则这部分转换开销就相对较大了,但使用带参数的宏定义就不会出现这个问 题 , 因为它是在预处理阶段即进行了宏展开 , 在执行时不需要转换,即在当地执行 。宏定义可完成简单的操作,但复杂的操作还是要由函数调用来完成,而且宏定义 所占用的目标代码空间相对较大 。所以在使用时要依据具体情况来决定是否使用宏定义 。
形式参数不能用带引号的字符串替换 。
但是,如果在替换文本中,参数名以#作为前缀则结果将被扩展为 由 实际参数 替换 此实际参数的带引号的字符串 。
例如,可以将它与字符串连接运算结合起来编写一个调试打印宏:
#define dprint(expr) printf(#expr “ = %\n”,expr)
使用语句 dprint(x/y);
调用宏时,该宏将被扩展为:printf(“x/y”“ = %\n”,x/y);
其中的字符串被连接起来了,这样便等价于printf(“x/y = %\n”,x/y);
在实际参数中,每个双引号 “ 将被替换为 \” ;反斜杠\将被替换为\\,因此替换后的字符串是合法的字符串常量 。
预处理运算符 ## 为宏扩展提供了一种连接实际参数的手段 。如果替换文本中的参数与 ## 相邻,则该参数将被实际参数替换,##与前后的空白符将被删除,并对替换后的结果重新扫描 。
例如,下面定义的宏paste用于连接两个参数
#define paste(front, back) front ## back
因此,宏调用past(name,1)的结果将建立记号name1.
c语言中没有swap这个函数,C语言不支持重载 , 也没有模版的概念,所以对于每一种类型,都要写出相应的swap,如
intSwap(int*,int*);
longSwap(long*,long*);
stringSwap(char*,char*);
宏定义swap(t,x , y)以交换t类型的两个参数(要使用程序块结构) 。
程序如下:
#include iostream.h
#define SWAP(t,x,y) \
{\
t temp = *y;\
*y = *x;\
*x = temp;\
}
main()
{
int a = 10, b = 5;
SWAP(int,a,b)
coutaendlbendl;
}
用\换行,\的意思是说把下一行看作和这行是同一行.换行必须要反斜杠,而且\後面直接回车,不能有空格 。
c语言函数#define作用define是C语言中的预处理命令,它用于宏定义,可以提高源代码的可读性,为编程提供方便 。预处理命令以“#”号开头,如包含命令#include,宏定义命令#define等 。一般都放在源文件的前面,它们称为预处理部分 。所谓预处理是指在进行编译之前所作的工作 。预处理是C语言的一个重要功能,它由预处理程序负责完成 。当对一个源文件进行编译时 , 系统将自动引用预处理程序对源程序中的预处理部分作处理,处理完毕自动进入对源程序的编译 。宏的定义 在C或C语言源程序中允许用一个标识符来表示一个字符串,称为“宏” 。被定义为“宏”的标识符称为“宏名” 。在编译预处理时,对程序中所有出现的“宏名”,都用宏定义中的字符串去代换,这称为“宏代换”或“宏展开” 。宏定义是由源程序中的宏定义命令完成的 。宏代换是由预处理程序自动完成的 。在C或C语言中,“宏”分为有参数和无参数两种 。无参数宏定义 无参数宏就是不带参数,其定义的一般形式为: #define 标识符 字符串 “标识符”为所定义的宏名 。“字符串”可以是常数、表达式、格式串等 。例如: #define PI 3.14 它的作用是指定标识符PI来代替常数3.14 。在编写源程序时 , 所有用到3.14的地方都可用PI代替,而对源程序作编译时,将先由预处理程序进行宏代换,即用3.14去置换所有的宏名PI,然后再进行编译 。宏定义是用宏名来表示一个字符串 , 在宏展开时又以该字符串取代宏名,这只是一种简单的代换,字符串可以是常数,也可以是表达式,预处理程序对它不作任何检查 。如有错误,只能在编译已被宏展开后的源程序时发现 。宏定义不是说明或语句(它是预处理指令) , 在行末不必加分号,如加上分号则连分号也一起置换 。下面举一个无参数宏替代常数的例子:#define PI 3.14 #include stdio.hint main() { float r = 1.0; float area = PI*r*r; printf("The area of the circle is %f",area); return 0; } 再举一个使用无参数宏替代字符串的例子: #define M (y*y 3*y) #include stdio.h int main() { int s,y; printf("input a number: "); scanf("%d",y); s = 3*M4*M5*M; printf("s=%d\n",s); return 0; } # define M (y*y 3*y) 定义M表达式(y*y 3*y) 。在编写源程序时,所有的(y*y 3*y)都可由M代替,而对源程序作编译时 , 将先由预处理程序进行宏代换,即用 (y*y 3*y)表达式去置换所有的宏名M,然后再进行编译 。上例程序中首先进行宏定义,定义M表达式(y*y 3*y),在s= 3*M 4*M 5* M中作了宏调用 。在预处理时经宏展开后该语句变为:s=3*(y*y 3*y) 4* (y*y 3*y) 5* (y*y 3*y);但要注意的是 , 在宏定义中表达式(y*y 3*y)两边的括号不能少 。否则会发生错误 。带参数宏定义 C语言允许宏带有参数 。在宏定义中的参数称为形式参数,在宏调用中的参数称为实际参数 。对带参数的宏,在调用中,不仅要宏展开,而且要用实参去代换形参 。带参数宏定义的一般形式为: #define 宏名(形参表) 字符串 在字符串中含有各个形参 。带参数宏调用的一般形式为: 宏名(实参表) 例如: #define M(y) y*y 3*y .... k=M(5); .... 在宏调用时,用实参5去代替形参y , 经预处理宏展开后的语句为: k=5*5 3*5 举一个具体例子: #define MAX(a,b) (ab)?a:b #include stdio.h int main() { int x,y,max; printf("input two numbers: "); scanf("%d%d",x,y); max = MAX(x,y); printf("max=%d\n",max); return 0; } 上例程序的第一行进行带参数宏定义,用宏名MAX表示条件表达式(ab)?a:b,形参a,b均出现在条件表达式中 。程序第七行max = MAX(x, y)为宏调用 , 实参x,y,将代换形参a,b 。宏展开后该语句为: max = (xy)?x:y;用于计算x,y中的大数 。对于带参的宏定义有以下问题需要说明: 1. 带参宏定义中,宏名和形参表之间不能有空格出现 。例如把: #define MAX(a,b) (ab)?a:b写为: #define MAX (a,b) (ab)?a:b 将被认为是无参宏定义,宏名MAX代表字符串 (a,b)(ab)?a:b 。宏展开时,宏调用语句: max = MAX(x,y);将变为: max = (a,b)(ab)?a:b(x,y);这显然是错误的 。2. 在宏定义中的形参是标识符 , 而宏调用中的实参可以是表达式 。#define SQ(y) (y)*(y) #include stdio.h int main() { int a,sq; printf("input a number: "); scanf("%d",a); sq=SQ(a 1); printf("sq=%d\n",sq); return 0; } 上例中第一行为宏定义,形参为y 。程序第七行宏调用中实参为a 1,是一个表达式 , 在宏展开时,用a 1代换y,再用(y)*(y) 代换SQ,得到如下语句: sq=(a 1)*(a 1); 这与函数的调用是不同的,函数调用时要把实参表达式的值求出来再赋予形参 。而宏代换中对实参表达式不作计算直接地照原样代换 。3. 在宏定义中,字符串内的形参通常要用括号括起来以避免出错 。在上例中的宏定义中(y)*(y)表达式的y都用括号括起来 , 结果是正确的 。如果去掉括号,把程序改为以下形式: #define SQ(y) y*y #include stdio.h int main() { int a,sq; printf("input a number: "); scanf("%d",a); sq=SQ(a 1); printf("sq=%d\n",sq); return 0; } 运行结果为:input a number:3 sq=7 (我们期望的结果却是16) 。问题在哪里呢? 这是由于代换只作符号代换而不作其它处理而造成的 。宏代换后将得到以下语句: sq=a 1*a 1; 由于a为3故sq的值为7 。这显然与题意相违,因此参数两边的括号是不能少的 。有时候 , 即使在参数两边加括号还是不够的,请看下面程序: #define SQ(y) (y)*(y) #include stdio.h int main() { int a,sq; printf("input a number: "); scanf("%d",a); sq=160/SQ(a 1); printf("sq=%d\n",sq); return 0; } 本程序与前例相比,只把宏调用语句改为: sq=160/SQ(a 1); 运行本程序如输入值仍为3时,希望结果为10 。但实际运行的结果如下:input a number:3 sq=160 。为什么会得这样的结果呢?分析宏调用语句 , 在宏代换之后变为: sq=160/(a 1)*(a 1);a为3时,由于“/”和“*”运算符优先级和结合性相同,则先作160/(3 1)得40,再作40*(3 1)最后得160 。为了得到正确答案应在宏定义中的整个字符串外加括号,程序修改如下: #define SQ(y) ((y)*(y)) #include stdio.h int main() { int a,sq; printf("input a number: "); scanf("%d",a); sq=160/SQ(a 1); printf("sq=%d\n",sq); return 0; } 以上讨论说明,对于宏定义,保险的做法是不仅应在参数两侧加括号,也应在整个字符串外加括号 。4. 带参数的宏和带参函数很相似,但有本质上的不同 , 把同一表达式用函数处理与用宏处理两者的结果有可能是不同的 。下面举一个例子进行对比:使用函数: #include stdio.h int SQ(int); int main() { int i=1; while(i=5) printf("%d\n",SQ(i)); return 0; } int SQ(int y) { return((y)*(y)); }使用宏: #define SQ(y) ((y)*(y)) #include stdio.h int main() { int i=1; while(i=5) printf("%d\n",SQ(i)); return 0; } 在使用函数的例子中函数名为SQ,形参为Y,函数体表达式为((y)*(y)) 。在使用宏的例子中宏名为SQ,形参也为y,字符串表达式为(y)*(y)) 。两例表面是相同的,函数调用为SQ(i),宏调用为SQ(i),实参也是相同的 。但输出结果却大不相同,分析如下: 在使用函数的例子中,函数调用是把实参i值传给形参y后自增1 。然后输出函数值 。因而要循环5次 。输出1~5的平方值 。而在使用宏的例子中 , 宏调用时,只作代换 。SQ(i)被代换为((i)*(i)) 。在第一次循环时,由于i等于1,其计算过程为:表达式中前一个i初值为1,然后i自增1变为2,因此表达式中第2个i初值为2,两相乘的结果也为2,然后i值再自增1,得3 。在第二次循环时,i值已有初值为3,因此表达式中前一个i为3,后一个i为4,乘积为12 , 然后i再自增1变为5 。进入第三次循环,由于i 值已为5 , 所以这将是最后一次循环 。计算表达式的值为5*6等于30 。i值再自增1变为6,不再满足循环条件,停止循环 。从以上分析可以看出函数调用和宏调用二者在形式上相似,在本质上是完全不同的 。"\","#","#@" 和"##" 在用#define 定义时 , 斜杠("\")是用来续行的,"#"用来把参数转换成字符串,是给参数加上双引号 。"##"则用来连接前后两个参数,把它们变成一个字符串,"#@"是给参数加上单引号 。下面的例子会使您很容易理解 。#define Conn(x,y) x##y #define ToChar(a) #@a#define ToString(x) #xint n = Conn(123,456); 结果就是n=123456; char* str = Conn("asdf", "adf")结果就是 str = "asdfadf"; char a = ToChar(1);结果就是a='1'; char* str = ToString(123132);就成了str="123132"; 为什么需要”#”,” #@”和”##”这三个操作符呢?原因如下: 宏名在源程序中若用引号括起来,则预处理程序不对其作宏代换 。如下: #define OK 100 #include stdio.h int main() { printf("OK"); printf("\n"); return 0; } 上例中定义宏名OK表示100 , 但在printf语句中OK被引号括起来,因此不作宏代换 。程序的运行结果为:OK,这表示把“OK”当字符串处理 。同样,宏名在源程序中若用单引号括起来,则预处理程序也不对其作宏代换 。宏定义的嵌套 宏定义允许嵌套,在宏定义的字符串中可以使用已经定义的宏名 。在宏展开时由预处理程序层层代换 。例如: #define PI 3.1415926 #define S PI*y*y 对语句: printf("%f",s); 在宏代换后变为: printf("%f",3.1415926*y*y); 结束语 使用宏代替一个在程序中经常使用的常量 , 这样该常量改变时,不用对整个程序进行修改,只修改宏定义的字符串即可 , 而且当常量比较长时,我们可以用较短的有意义的标识符来写程序,这样更方便一些 。举一个大家比较熟悉的例子,圆周率π是在数学上常用的一个值,有时我们会用3.14来表示 , 有时也会用3.1415926等,这要看计算所需要的精度 , 如果我们编制的一个程序中要多次使用它,那么需要确定一个数值,在本次运行中不改变,但也许后来发现程序所表现的精度有变化,需要改变它的值 , 这就需要修改程序中所有的相关数值,这会给我们带来一定的不便,但如果使用宏定义,使用一个标识符来代替 , 则在修改时只修改宏定义即可,还可以减少输入 3.1415926这样长的数值多次的情况,我们可以如此定义 #define pi 3.1415926 , 既减少了输入又便于修改,何乐而不为呢? 另外,使用带参数的宏定义可完成函数调用的功能,又能减少系统开销,提高运行效率 。正如C语言中所讲,函数的使用可以使程序更加模块化,便于组织,而且可重复利用,但在发生函数调用时,需要保留调用函数的现?。员阕雍葱薪崾竽芊祷丶绦葱?nbsp;, 同样在子函数执行完后要恢复调用函数的现场,这都需要一定的时间 , 如果子函数执行的操作比较多,这种转换时间开销可以忽略,但如果子函数完成的功能比较少,甚至于只完成一点操作,如一个乘法语句的操作,则这部分转换开销就相对较大了,但使用带参数的宏定义就不会出现这个问题,因为它是在预处理阶段即进行了宏展开,在执行时不需要转换,即在当地执行 。宏定义可完成简单的操作,但复杂的操作还是要由函数调用来完成 , 而且宏定义所占用的目标代码空间相对较大 。所以在使用时要依据具体情况来决定是否使用宏定义 。
define函数块c语言的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于c语言中define简单使用实例、define函数块c语言的信息别忘了在本站进行查找喔 。
推荐阅读
- 什么软件适合画胶带视频,什么软件适合画胶带视频教学
- 直播间内放音乐软件叫什么,直播中放音乐
- 格斗游戏等级,格斗级别划分以什么来划分的
- 营销会计如何与业务员沟通,会计营销话术
- 如何终止oracle运行 oracle怎么停止sql执行
- 营销员如何面对客户挑战,营销客户技巧
- 新媒体上班待遇如何知乎,新媒体工资待遇怎么样
- 电视自带的极光怎么用,极光电视机
- php怎么批量增加数据库 php批量更新数据库