关于C语言的编译和链接

预定义符号:

在C语言中,有这么一些预定义符号是C语言内置的:

__FILE__ //进行编译的源文件(这些__其实是由两个下划线组成的)
__LINE__ //文件当前的行号
__DATE__ //文件被编译的日期
__TIME__ //文件被编译的时间
__STDC__ //如果编译器遵循ANSI C,其值为1,否则未定义

举个小例子: 

int main()
{
	printf("%s", __DATE__);
	return 0;
}

#define定义标识符

语法:
#define name stuff 

#define MAX 100

首先来看这个举例:

int main()
{
	int a = 10;
	int ret = a * a;
	printf("%d", ret);
	return 0;
}一般我们都是这样写的

但是我们可以用#define来定义,请看如下:

#define MAX 10
int main()
{
	int ret = MAX * MAX;
	printf("%d", ret);
	return 0;
}

这样所有MAX的地方都被替换成了10


#define reg register //为 register这个关键字,创建一个简短的名字

可以用这种方法将代码中的register全部替换成reg,不用一个一个单独修改


// 如果定义的 stuff过长,可以分成几行写,除了最后一行外,每行的后面都加一个反斜杠(续行符)。
#define DEBUG_PRINT printf("file:%s\tline:%d\t \
date:%s\ttime:%s\n" ,\
__FILE__,__LINE__ , \
__DATE__,__TIME__ )

切记:定义#define的时候,最后最好别加;(分号)

举个例子:

int array[MAX];
如果在 #define MAX 10 后面误加了分号 ;,虽然大部分编译器可能不会报错,但这个分号在这里是不必要的,并且不推荐这种做法。

#define定义宏

下面是宏的申明方式:

#define name( parament-list ) stuff
其中的 parament-list 是一个由逗号隔开的符号表,它们可能出现在stuff中

注意:
参数列表的左括号必须与name紧邻。
如果两者之间有任何空白存在,参数列表就会被解释为stuff的一部分

来实战一下吧:

#define NUM(x) x*x
int main()
{
	int a = 5;
	printf("%d", NUM(a));
	return 0;
}

这个宏接收一个参数 x 如果在上述声明之后,你把置于程序中,预处理器就会用下面这个表达式替换上面的表达式,结果为25

那么我们将这段代码稍加修改呢?结果会是怎样的

#define NUM(x) x*x
int main()
{
	int a = 5;
	printf("%d", NUM(a+1));//我们传一个表达式a+1
	return 0;
}

乍一看是不是感觉没问题,按照我们目前的理解应该是36对吧,可是并不是,让我来给大家解释一下吧,上图!

说了这么一大堆,我们应该怎样得到正确的结果呢?

其实特别简单,我们只需要这样定义

#define SQUARE(x) (x) * (x)

 加个()来保证a+1是一个整体,这样预处理之后就变成了这样:

printf ("%d\n",(a + 1) * (a + 1) );

那么这里还有一个宏定义,让我们来看一下吧!

#define DOUBLE(x) (x) + (x)

定义中我们使用了括号,想避免之前的问题,但是这个宏可能会出现新的错误。

int a = 5;
printf("%d\n" ,10 * DOUBLE(a))

看上去,好像打印100,但事实上打印的是55,我们发现替换之后:

printf ("%d\n",10 * (5) + (5));

那这个又该怎么解决了,其实更简单,只需要在两边都加上()就行

#define DOUBLE(x) ((x)+(x))

tip:所以用于对数值表达式进行求值的宏定义都应该用这种方式加上括号,避免在使用宏时由于参数中的操作符或邻近操作符之间不可预料的相互作用。

#define 替换规则

1. 宏参数和#define 定义中可以出现其他#define定义的符号。但是对于宏,不能出现递归。
2. 当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索。

特殊操作符:

#(字符串化操作符): 当你在宏定义中使用 # 时,它会将宏参数转换为一个字符串字面量。

#define PRINT(FORMAT, VALUE)\
printf("the value is "FORMAT"\n", VALUE);
PRINT("%d", 10);

代码中的 #VALUE 会预处理器处理为:"VALUE"

最终的输出的结果应该是:

the value of i+3 is 13

 

##(连接操作符): 宏定义中的 ## 用于连接两个符号。它通常与宏参数一起使用来创建新的标识符或表达式。

#define ADD_TO_SUM(num, value) \
sum##num += value;
ADD_TO_SUM(5, 10);//作用是:给sum5增加10.

注意:这样的连接必须产生一个合法的标识符。否则其结果就是未定义的。

带副作用的宏参数:

x+1;//不带副作用
x++;//带有副作用

#define MAX(a, b) ( (a) > (b) ? (a) : (b) )
...
x = 5;
y = 8;
z = MAX(x++, y++);
printf("x=%d y=%d z=%d\n", x, y, z);//输出的结果是什么?

这里我们得知道预处理器处理之后的结果是什么:

z = ( (x++) > (y++) ? (x++) : (y++));

结果为:x=6 y=10 z=9

根本不符合我们的预期,所以我们最好别使用这种带副作用的

宏和函数对比


1. 用于调用函数和从函数返回的代码可能比实际执行这个小型计算工作所需要的时间更多。
所以宏比函数在程序的规模和速度方面更胜一筹。
2. 更为重要的是函数的参数必须声明为特定的类型。
所以函数只能在类型合适的表达式上使用。反之这个宏怎可以适用于整形、长整型、浮点型等可以
用于>来比较的类型。
宏是类型无关的。

宏的缺点:当然和函数相比宏也有劣势的地方:

  1.  每次使用宏的时候,一份宏定义的代码将插入到程序中。除非宏比较短,否则可能大幅度增加程序的长度。
  2. .宏是没法调试的。
  3. 宏由于类型无关,也就不够严谨。
  4.  宏可能会带来运算符优先级的问题,导致程容易出现错。

命名约定

一般来讲函数的宏的使用语法很相似。所以语言本身没法帮我们区分二者。
那我们平时的一个习惯是:
把宏名全部大写
函数名不要全部大写

#undef

这条指令用于移除一个宏定义。

#undef NAME
//如果现存的一个名字需要被重新定义,那么它的旧名字首先要被移除。

  • 22
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
信息数据从传统到当代,是一直在变革当中,突如其来的互联网让传统的信息管理看到了革命性的曙光,因为传统信息管理从时效性,还是安全性,还是可操作性等各个方面来讲,遇到了互联网时代才发现能补上自古以来的短板,有效的提升管理的效率和业务水平。传统的管理模式,时间越久管理的内容越多,也需要更多的人来对数据进行整理,并且数据的汇总查询方面效率也是极其的低下,并且数据安全方面永远不会保证安全性能。结合数据内容管理的种种缺点,在互联网时代都可以得到有效的补充。结合先进的互联网技术,开发符合需求的软件,让数据内容管理不管是从录入的及时性,查看的及时性还是汇总分析的及时性,都能让正确率达到最高,管理更加的科学和便捷。本次开发的医院后台管理系统实现了病房管理、病例管理、处方管理、字典管理、公告信息管理、患者管理、药品管理、医生管理、预约医生管理、住院管理、管理员管理等功能。系统用到了关系型数据库中王者MySql作为系统的数据库,有效的对数据进行安全的存储,有效的备份,对数据可靠性方面得到了保证。并且程序也具备程序需求的所有功能,使得操作性还是安全性都大大提高,让医院后台管理系统更能从理念走到现实,确确实实的让人们提升信息处理效率。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值