基本标示符-宏-编译连接

来源:互联网 发布:软件升级服务合同 编辑:程序博客网 时间:2024/06/07 05:14

    励志做一个文艺程序员的我,发现自己还是缺少文艺细胞,所以博客名字非常直白,就是来说一说基本标示符合宏以及编译连接的过程。

    首先是基本标示符,这就简单来谈四个:__FILE__,__LINE__,__DATE__,__TIME__.

    第一个:__FILE__:顾名思义就是文件的存储位置,这个在打印语句中是用%s来输出的;

    第二个:__LINE__:这个就是此时你的打印语句在这个C程序的第几行,用%d显示;

    第三个:__DATE__:这个是显示当前的日期,包括年份、月份和日期,因为是英文的缘故,是按年,日,月来输出的;

    第四个:__TIME__:这个用来显示当前的时间。

以下是代码实现

#define _CRT_SECURE_NO_WARNINGS#include<stdio.h>int main(){printf("%s\n %d\n %s\n %s\n",__FILE__,__LINE__,__DATE__,__TIME__);system("pause");return 0;}
    这个就十分简单了,就不多说了。

    现在说宏,宏有很多作用,但大家平时用得最多的就是定义一个全部变量。例如:

#define M 10  //这个就是这个C文件中想用10时,采用M就行,加深了代码的灵活性
    除了这个,宏还有很多的作用,并且宏是在预处理阶段进行的,即编译阶段就会将宏的作用体现,这个在VS里面没法看,在linux里面会发现gcc编译之后就会发现.i文件中已经实现了宏。

    要注意的是,在宏里定义时,要养成一个加小括号的习惯,例如

#define ADD(a,b)  a * b
    假如是3*5的话,会正确是输出15,但是如果a为1+2,b是4+1时,这个时候的逻辑就是1+2 * 4+1 ,这个时候的优先级是先乘法再加法,结果就是10,而不是需要的15,但如果加括号的话就是(1+2)*(4+1),出来的就是15了,同理,为了防止其他的问题,也应该给整个式子加上括号((1+2)*(4+1))。

    宏在定义函数时,要进行do{函数1,函数2,...,函数n;}while(0)的操作,为的是防止函数后面的分号,和main函数里面的分号产生冲突。例如:

#define name do{函数1,函数2,...,函数n;}while(0)int main (){     name;    return 0;}
    这时就不用在意分号了(只要你输入无误)。

    同样,宏里面还能定义字符串。例如“

#define str “Hello”int mian (){    printf("str"world " \n");    return 0;}

    此时,因为宏定义的邻近字符串的连接特性,可以直接采用str,而不用给str带上双引号。

    宏定义里面还可以将两个连接成一个,说起来可能不是很好表达,大家看一下代码

#define M  "Hello "
#define N  "World "
#define MN "Hello World "
#define LINK(x,y)  x##y
int main()
{
    printf("%s",LINK(M, N));//此时输出就会是完整的"Hello World "
    return 0;
}
    宏的定义还有很重要的一点,那就是条件编译,这个在我们写代码,项目的时候对我们非常有帮助,一方面可以防止头文件被重复调用,另一方面可以让我们将宏用的更加灵活,对宏的定义也更深刻,下面的也只是我的一点理解,有不足的地方还请告知。

    例如:#define后一个名称,用到一半,在下面的文件中发现还有别的函数或者变量更适合这个名字,此时你可以用#undef来移除这个宏定义,那么之前你定义的那个宏定义就会失去作用,但在#undef之前还可以使用。但是这个不建议使用,假如你这样使用,或许别人有时会忽略或者没看到中间的#undef,那么会一直以为你的宏定义是之前的意思,容易造成误解,  不过要是只有你自己看的话那就随便咯。

   还可以用来检测是否被定义

#if  !define(symbel)   //检测symbel是否被定义,没有定义的话执行下面的语句
#define  symbel    //没有定义,测定义symbel
另一个作用:

//1
#define NAME ...  //定义NAME

#if  NAME  语句1   //若NAME为真,则输出语句1
#endif
//2
<pre name="code" class="html">#define NAME ...  //定义NAME
#if  NAME  语句1   //若NAME为真,则输出语句1
#elif NAME1  语句2   //若NAME1为真,则输出语句1
#elif NAME2   语句3    //若NAME2为真,则输出语句1
...
#endif


编译连接:

     说实话。我对这个也不是很了解,而仅有的这些还是在Linux上了解的,首先建立好一个简单的C文件之后,编译这个文件,这时会进行预处理,而预处理会进行四项活动分别是:头文件展开、去注释、宏替换、条件编译。这些在linux上你将.c文件转为.i文件后可以看见采用gcc -E test.c -o test.i语句,再使用cat test.i可以进入.i文件进行查看,假如你还觉得不是很贴近计算机的方式还可以用gcc -S test.i -o tets.s,再用cat test.s进行查看汇编语言,要是你还觉得不过瘾,那就gcc -c test.s -o test.o,再用cat查看8进制或者16进制的01序列吧。

    而且,本地中有很多头文件还有库函数,在编译期间并没有将这些东西编译进去,那么会在什么时候起作用呢?会在链接时,将你自己的C文件编译完成没有错误之后,和这写库函数进行统一的链接,形成一个完整的可执行文件,把可执行程序需要的所有编译过程产生的.o或者obj文件组合到一起(包括.lib),另外连接过程还会组合一些其他数据,比如次元,可执行文件头等。












0 0
原创粉丝点击