网站建设页面,合川网站优化,wordpress 只显示摘要,个人网站空间#x1f307;个人主页#xff1a;平凡的小苏 #x1f4da;学习格言#xff1a;别人可以拷贝我的模式#xff0c;但不能拷贝我不断往前的激情 #x1f6f8;C语言专栏#xff1a;https://blog.csdn.net/vhhhbb/category_12174730.html 小苏希望大家能从这篇文章中收获到许…  个人主页平凡的小苏 学习格言别人可以拷贝我的模式但不能拷贝我不断往前的激情 C语言专栏https://blog.csdn.net/vhhhbb/category_12174730.html 小苏希望大家能从这篇文章中收获到许多如果大家觉得这篇文章对你有帮助请给小苏点赞收藏评论 目录 
1. 程序的翻译环境和执行环境  
2. 详解编译链接  
2.1 翻译环境 2.2 编译本身也分为几个阶段 
2.3 运行环境   
3. 预处理详解 
3.1 预定义符号 3.2 #define 
3.2.1 #define 定义标识符 
3.2.2 #define 定义宏  2.2.3 #define 替换规则 
3.2.4 #和##   
3.2.5 带副作用的宏参数   
3.2.6 命名约定  
3.3 #undef   
3.4 命令行定义 
3.5 条件编译 1. 程序的翻译环境和执行环境  
在ANSI C的任何一种实现中存在两个不同的环境。第1种是翻译环境在这个环境中源代码被转换为可执行的机器指令。  第2种是执行环境它用于实际执行代码。  2. 详解编译链接  
2.1 翻译环境 
  
组成一个程序的每个源文件通过编译过程分别转换成目标代码object code。 每个目标文件由链接器linker捆绑在一起形成一个单一而完整的可执行程序。 链接器同时也会引入标准C函数库中任何被该程序所用到的函数而且它可以搜索程序员个人 的程序库将其需要的函数也链接到程序中 
编译分为三步骤如下图所示  2.2 编译本身也分为几个阶段 1. 预处理 选项 gcc -E test.c -o test.i      预处理完成之后就停下来预处理之后产生的结果都放在test.i文件中。  2. 编译 选项 gcc -S test.c      编译完成之后就停下来结果保存在test.s中。  3. 汇编 gcc -c test.c      汇编完成之后就停下来结果保存在test.o中 2.3 运行环境   
程序执行的过程1. 程序必须载入内存中。在有操作系统的环境中一般这个由操作系统完成。在独立的环境中程序的载入必须由手工安排也可能是通过可执行代码置入只读内存来完成。  2. 程序的执行便开始。接着便调用main函数。   3. 开始执行程序代码。这个时候程序将使用一个运行时堆栈stack存储函数的局部变量和返回地址。程序同时也可以使用静态static内存存储于静态内存中的变量在程序的整个执行过程一直保留他们的值。  4. 终止程序。正常终止main函数也有可能是意外终止。   3. 预处理详解  3.1 预定义符号    __FILE__      //进行编译的源文件  __LINE__     //文件当前的行号  __DATE__    //文件被编译的日期  __TIME__    //文件被编译的时间  __STDC__    //如果编译器遵循ANSI C其值为1否则未定义     举个栗子这些预定义符号都是内置的 
#includestdio.h
int main()
{printf(file:%s line:%d\n, __FILE__, __LINE__);return 0;
} 这两个预定义符号会在屏幕打印出源文件路径和该代码在哪一行  3.2 #define  
3.2.1 #define 定义标识符  
提问在define定义标识符的时候要不要在最后加上 ; ?比如 #define MAX 1000;
#define MAX 1000  建议不要加上 ; ,这样容易导致问题。 
比如下面的场景 
if(condition)max  MAX;elsemax  0; 这里会出现语法错误。 3.2.2 #define 定义宏  
#define 机制包括了一个规定允许把参数替换到文本中这种实现通常称为宏macro或定义 宏define macro。下面是宏的申明方式 #define name( parament-list ) stuff  其中的 parament-list 是一个由逗号隔开的符号表它们可能出现在stuff中。  注意  参数列表的左括号必须与name紧邻。  如果两者之间有任何空白存在参数列表就会被解释为stuff的一部分。  如  #define SQUARE( x ) x * x 这个宏接收一个参数 x . 如果在上述声明之后你把SQUARE( 5 ); 置于程序中预处理器就会用下面这个表达式替换上面的表达式。    警告  这个宏存在一个问题  观察下面的代码段     int a  5;
printf(%d\n ,SQUARE( a  1) ); 替换文本时参数x被替换成a  1,所以这条语句实际上变成了  printf (%d\n,a  1 * a  1 );   这样就比较清晰了由替换产生的表达式并没有按照预想的次序进行求值。  在宏定义上加上两个括号这个问题便轻松的解决了   2.2.3 #define 替换规则 
在程序中扩展#define定义符号和宏时需要涉及几个步骤。 在调用宏时首先对参数进行检查看看是否包含任何由#define定义的符号。如果是它们首先被替换。 替换文本随后被插入到程序中原来文本的位置。对于宏参数名被他们的值所替换。 最后再次对结果文件进行扫描看看它是否包含任何由#define定义的符号。如果是就重复上述处理过程。注意  1. 宏参数和#define 定义中可以出现其他#define定义的符号。但是对于宏不能出现递归。  2. 当预处理器搜索#define定义的符号的时候字符串常量的内容并不被搜索。 3.2.4 #和##   如何把参数插入到字符串中  首先我们看看这样的代码 char* p  hello bit\n;
printf(hello bit\n);
printf(%s, p); 这里输出的是不是  hello bit   答案是确定的是。  我们发现字符串是有自动连接的特点的。    1.使用 # 把一个宏参数变成对应的字符串  int i  10;
#define PRINT(FORMAT, VALUE)\printf(the value of  #VALUE is FORMAT \n, VALUE);
...
PRINT(%d, i3);//产生了什么效果 最终的输出的结果应该是    the value of i3 is 13      ## 的作用  ##可以把位于它两边的符号合成一个符号。  它允许宏定义从分离的文本片段创建标识符。  #define ADD_TO_SUM(num, value) \sum##num  value;
...
ADD_TO_SUM(5, 10);//作用是给sum5增加10. 注 这样的连接必须产生一个合法的标识符。否则其结果就是未定义的。  3.2.5 带副作用的宏参数   
当宏参数在宏的定义中出现超过一次的时候如果参数带有副作用那么你在使用这个宏的时候就可能出现危险导致不可预测的后果。副作用就是表达式求值的时候出现的永久性效果。 例如 x1;//不带副作用  x;//带有副作用   MAX宏可以证明具有副作用的参数所引起的问题。   #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));   所以输出的结果是 x6 y10 z9  3.2.6 命名约定  
一般来讲函数的宏的使用语法很相似。所以语言本身没法帮我们区分二者。 那我们平时的一个习惯是 把宏名全部大写  函数名不要全部大写   3.3 #undef   
这条指令用于移除一个宏定义。3.4 命令行定义 许多C 的编译器提供了一种能力允许在命令行中定义符号。用于启动编译过程。  例如当我们根据同一个源文件要编译出一个程序的不同版本的时候这个特性有点用处。假如某个 程序中声明了一个某个长度的数组如果机器内存有限我们需要一个很小的数组但是另外一个机器内存大些我们需要一个数组能够大些。  3.5 条件编译 在编译一个程序的时候我们如果要将一条语句一组语句编译或者放弃是很方便的。因为我们有条件编译指令。  比如说  调试性的代码删除可惜保留又碍事所以我们可以选择性的编译。   常见的条件编译指令 
1.
#if 常量表达式//...
#endif
//常量表达式由预处理器求值。
如
#define __DEBUG__ 1
#if __DEBUG__//..
#endif
2.多个分支的条件编译
#if 常量表达式//...
#elif 常量表达式//...
#else//...
#endif
3.判断是否被定义
#if defined(symbol)
#ifdef symbol
#if !defined(symbol)
#ifndef symbol
4.嵌套指令
#if defined(OS_UNIX)#ifdef OPTION1unix_version_option1();#endif#ifdef OPTION2unix_version_option2();#endif
#elif defined(OS_MSDOS)#ifdef OPTION2msdos_version_option2();#endif
#endif 注这里#undef是取消#define的定义  #ifdef 是判断有没有进行宏定义如果没有定义则就不执行#ifdef里面的语句#ifdef和#endif是配套使用的 好了小编的分享到这里就结束了有什么不足的地方请大佬多多指正