程序的环境与预处理 程序的编译与链接

文章详细介绍了C语言程序的翻译和执行环境,包括编译和链接的过程,以及预处理的概念,如预定义符号、宏定义、条件编译和文件包含。预处理在GCC中的选项如-E、-S和-o分别对应预处理、编译和汇编阶段。文章强调了宏与函数的区别,以及宏可能带来的问题,如类型安全和代码膨胀,并提到了防止头文件重复包含的技巧。
摘要由CSDN通过智能技术生成

目录

 1.程序的翻译环境和执行环境

​编辑

2.编译+链接 

运行环境

3.预处理

预定义符号

#define 

#与##

带副作用的宏参数

宏和函数的对比 

命名约定

​编辑

 #undef​编辑

命令行定义

 ​编辑

 条件编译

文件包含

嵌套文件包含 

4.其他预处理指令


 1.程序的翻译环境和执行环境


在ANSL C的任何一种实现中,存在两个不同的环境
第1种是翻译环境,在这个环境中源代码被转换为可执行的机器指令。
第2种是执行环境,它用于实际执行代码。

2.编译+链接 

组成一个程序的每个源文件通过编译过程分别转换成目标代码 (obiect code)

每个目标文件由链接器 (linker) 捆绑在一起,形成一个单一而完整的可执行程序。

链接器同时也会引入标准C函数库中任何被该程序所用到的函数,而且它可以搜索程序员个人的程序库,将其需要的函数也链接到程序中。

integrated development environment

 

 

  

1.预处理选项gcc -E test.c -o test.i
预处理完成之后就停下来,预处理之后产生的结果都放在test.i文件中
2.编译选项 gcc-S test.c
编译完成之后就停下来,结果保存在test.s中。
3.汇编gcc -c test.c
汇编完成之后就停下来,结果保存在test.o中 

链接阶段在符号表里查看,可以发现未定义的函数


运行环境


3.预处理

预定义符号

示例:


#define 

 示例:

 #define后面要加;吗?

 eg:#define MAX 100;

加了;就代表MAX被“100;”替换 可能引起语法错误呦


示例:

注意与函数的区别:

定义宏是直接替换,而不是像函数一样传具体的值 

那这样是不是就可以解决一些函数中类型不一样无法写成一个函数的问题捏?

是滴!

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

一些小小的注意事项:

示例:(X*X)  与 ((X)*(X)) 的区别


例题:

写一个宏,可以将一个整数的二进制位的奇数位和偶数位交换

再来一次,又改回去了


额外区别:

abc都是指针类型 只有b不是 (int_ptr 并不是简单的替换)


 

#与##

 

  示例:

宏替换

 #:替换参数对应的字符串 而不是值

替换之后如下:


 示例:(连接作用(将分离合成整体))(但合成的整体必须是有定义的)

打印出的结果为:100


带副作用的宏参数

 示例:


宏和函数的对比 

宏通常被应用于执行简单的运算

比如在两个数中找出较大的一个

#define MAX(a,b)   ((a)>(b)?(a):(b))

那为什么不用函数来完成这个任务?

 函数会:调用——>计算——>返回(小型运算)

宏的缺点:

当然和函数相比宏也有劣势的地方:
1.每次使用宏的时候,一份宏定义的代码将插入到程序中。除非宏比较短,否则可能大幅度增加程序的长度。
2.宏是没法调试的。

3.宏由于类型无关也就不够严谨

4.宏可能会带来运算符优先级的问题,导致程容易出现错

示例:


命名约定


 #undef

 示例:


命令行定义

 

 条件编译

 

示例:

3.判断是否被定义

#if defined(symbol)

#ifdef symbol


#if !defined(symbol)

#ifndef symbol


4.嵌套指令
#if defined(OS_UNIX)

       #ifdef OPTION1
                unix_version_option1();

       #endif

       #ifdef  OPTION2
               unix_version_option2();

      #endif
#elif defined(OS_MSDOS)

     #ifdef OPTION2
              msdos_version_option2();#endif
     #endif 

#endif

示例:

 上面两种写法等价

那条件编译与if else语句有何不同捏?

条件编译在预处理阶段就已经把不要的代码删掉了,而if else语句的代码还在留着


文件包含

文件包含
我们已经知道,#include 指令可以使另外一个文件被编译。就像它实际出现于#include 指令的地方
一样。

这种替换的方式很简单

预处理器先删除这条指令,并用包含文件的内容替换。这样一个源文件被包含10次,那就实际被编译10次。

VS环境的标准头文件的路径:
c:\Program Files (x86)\Microsoft visual studio 12.0\vc\include
//这是VS2013的默认路径

 

查找头文件直接去标准路径下去查找,如果找不到就提示编译错误。

这样是不是可以说,对于库文件也可以使用“”的形式包含?

答案是肯定的,可以。

但是这样做查找的效率就低些,当然这样也不容易区分是库文件还是本地文件了。

示例:


嵌套文件包含 

 如何解决这个问题?
答案:条件编译。
每个头文件的开头写

#ifndef  __TEST_H__

#define  __TEST_H__
//头文件的内容
#endif     //__TEST_H__


或者

#pragma once


就可以避免头文件的重复引入。

示例:


4.其他预处理指令

在VS中#pragma pack()可能会自动出现,不用重复的包含头文件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值