定西市小企业网站建设,网站引导页动态效果怎么做的,夏邑好心情网站建设有限公司,wordpress怎么做301重定向了解程序的运行环境可以让我们更加清楚的程序的底层运行的每一个步骤和过程#xff0c;做到心中有数#xff0c;预处理阶段是在预编译阶段完成#xff0c;掌握常用的预处理命令语法#xff0c;可以让我们正确的使用预处理命令#xff0c;从而提高代码的开发能力和阅读别人… 了解程序的运行环境可以让我们更加清楚的程序的底层运行的每一个步骤和过程做到心中有数预处理阶段是在预编译阶段完成掌握常用的预处理命令语法可以让我们正确的使用预处理命令从而提高代码的开发能力和阅读别人代码的能力本篇博客详细总结C语言中的程序环境和预处理达到理解并运用的目的 一、程序的翻译环境和执行环境 在ANSI C的任何一种实现中存在两个不同的环境。 第1种是翻译环境在这个环境中源代码被转换为可执行的机器指令。 第2种是执行环境它用于实际执行代码。 二、详细介绍编译链接
2.1 翻译环境 组成一个程序的每个源文件通过编译过程分别转换成目标代码object code。 每个目标文件由链接器linker捆绑在一起形成一个单一而完整的可执行程序。链接器同时也会引入标准C函数库中任何被该程序所用到的函数而且它可以搜索程序员个人 的程序库将其需要的函数也链接到程序中。 2.2 编译本身划分的阶段
看代码 sum.c文件
int g_val 2016;
void print(const char *str)
{printf(%s\n, str);
}
test.c文件
#include stdio.hextern void print(char *str);extern int g_val;int main()
{printf(%d\n, g_val);print(hello bit.\n);return 0;
}VIM学习资料 简明VIM练级攻略 https://coolshell.cn/articles/5426.html 给程序员的VIM速查卡 https://coolshell.cn/articles/5479.html 2.3 运行环境 程序执行的过程 程序必须载入内存中。在有操作系统的环境中一般这个由操作系统完成。在独立的环境中程序 的载入必须由手工安排也可能是通过可执行代码置入只读内存来完成。 程序的执行便开始。接着便调用main函数。开始执行程序代码。这个时候程序将使用一个运行时堆栈stack存储函数的局部变量和返回 地址。程序同时也可以使用静态static内存存储于静态内存中的变量在程序的整个执行过程 一直保留他们的值。 终止程序。正常终止main函数也有可能是意外终止。 三、预处理详细介绍
3.1 预定义符号 顾名思义预定义宏就是已经预先定义好的宏我们可以直接使用无需再重新定义。 举例
#include stdio.h
#include stdlib.hint main()
{printf(Date : %s\n, __DATE__);printf(Time : %s\n, __TIME__);printf(File : %s\n, __FILE__);printf(Line : %d\n, __LINE__);system(pause);return 0;
} 3.2 #define #define 叫做宏定义命令它也是C语言预处理命令的一种。所谓宏定义就是用一个标识符来表示一个字符串如果在后面的代码中出现了该标识符那么就全部替换成指定的字符串。 这里所说的字符串是一般意义上的字符序列不要和C语言中的字符串等同它不需要双引号。 3.2.1 #define 定义标识 语法格式#define 宏名 字符串 解释#表示这是一条预处理命令所有的预处理命令都以 # 开头。宏名是标识符的一种命名规则和变量相同。 注意两点 1.字符串可以是数字、表达式、if 语句、函数等。 2.宏定义不是说明或语句在行末不必加分号如加上分号则连分号也一起替换。建议不要加分号。 #include stdio.h#define N 100int main()
{int sum 20 N;printf(%d\n, sum);return 0;
}
注意第 6 行代码int sum 20 NN被100代替了。#define N 100就是宏定义N为宏名100是宏的内容宏所表示的字符串。在预处理阶段对程序中所有出现的“宏名”预处理器都会用宏定义中的字符串去代换这称为“宏替换”或“宏展开”。宏定义是由源程序中的宏定义命令#define完成的宏替换是由预处理程序完成的。 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 );
置于程序中预处理器就会用下面这个表达式替换上面的表达式5 * 5
警告上面这个宏存在一个问题
观察下面的代码段
int a 5;
printf(%d\n ,SQUARE( a 1) );
乍一看你可能觉得这段代码将打印36这个值。
事实上它将打印11.
为什么
替换文本时参数x被替换成a 1,所以这条语句实际上变成了
printf (%d\n,a 1 * a 1 );
这样就比较清晰了由替换产生的表达式并没有按照预想的次序进行求值。
在宏定义上加上两个括号这个问题便轻松的解决了#define SQUARE(x) (x) * (x)
这样预处理之后就产生了预期的效果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));
乘法运算先于宏定义的加法所以出现了55
这个问题的解决办法是在宏定义表达式两边加上一对括号就可以了。
#define DOUBLE(x) ( ( x ) ( x ) ) 总结提示 所以用于对数值表达式进行求值的宏定义都应该用这种方式加上括号避免在使用宏时由于参数中 的操作符或邻近操作符之间不可预料的相互作用。 3.2.3 #define 替换规则 在程序中扩展#define定义符号和宏时需要涉及几个步骤。 在调用宏时首先对参数进行检查看看是否包含任何由#define定义的符号。如果是它们首先被替换。 替换文本随后被插入到程序中原来文本的位置。对于宏参数名被他们的值所替换。最后再次对结果文件进行扫描看看它是否包含任何由#define定义的符号。如果是就重复上 述处理过程。 注意事项 1. 宏定义是用宏名来表示一个字符串在宏展开时又以该字符串取代宏名这只是一种简单粗暴的替换。字符串中可以含任何字符它可以是常数、表达式、if 语句、函数等预处理程序对它不作任何检查如有错误只能在编译已被宏展开后的源程序时发现。 2. 宏定义必须写在函数之外其作用域为宏定义命令起到源程序结束。如要终止其作用域可使用#undef命令 3. 代码中的宏名如果被引号包围那么预处理程序不对其作宏代替而作为字符串处理。 4. 宏定义允许嵌套在宏定义的字符串中可以使用已经定义的宏名在宏展开时由预处理程序层层代换。 5. 习惯上宏名用大写字母表示以便于与变量区别。 6. 可用宏定义表示数据类型使书写方便。但是需要注意用宏定义表示数据类型和用typedef定义数据说明符的区别。宏定义只是简单的字符串替换由预处理器来处理而 typedef 是在编译阶段由编译器处理的它并不是简单的字符串替换而给原有的数据类型起一个新的名字将它作为一种新的数据类型。(易出错点) #define UINT unsigned int
在程序中可用 UINT 作变量说明
UINT a, b; 请看下面表示整型指针类型的两种方式
#define PIN1 int *
typedef int *PIN2; //也可以写作typedef int (*PIN2);下面用 PIN1PIN2 说明变量时就可以看出它们的区别
PIN1 a, b; 在宏代换后变成int * a, b;表示 a 是指向整型的指针变量而 b 是整型变量。
然而
PIN2 a,b;
表示 a、b 都是指向整型的指针变量。因为 PIN2 是一个新的、完整的数据类型。由这个例子可见宏定义虽然也可表示数据类型 但毕竟只是简单的字符串替换。
在使用时要格外小心以避出错。 3.2.4 #和## 在宏定义中有时还会用到#和##两个符号它们能够对宏参数进行操作。 1. #的用法 #用来将宏参数转换为字符串也就是在宏参数的开头和末尾添加引号。 #define STR(s) #s
那么
printf(%s, STR(c.biancheng.net));
printf(%s, STR(c.biancheng.net));
分别被展开为
printf(%s, c.biancheng.net);
printf(%s, \c.biancheng.net\);
可以发现即使给宏参数“传递”的数据中包含引号
使用#仍然会在两头添加新的引号而原来的引号会被转义。 #include stdio.h
#define STR(s) #s
int main(){printf(%s\n, STR(c.biancheng.net));printf(%s\n, STR(c.biancheng.net));return 0;
} 运行结果 c.biancheng.net c.biancheng.net 2. ##用法 ##称为连接符用来将宏参数或其他的串连接起来。 #define CON1(a, b) a##e##b
#define CON2(a, b) a##b##00那么
printf(%f\n, CON1(8.5, 2));
printf(%d\n, CON2(12, 34));
将被展开为
printf(%f\n, 8.5e2);
printf(%d\n, 123400); #include stdio.h
#define CON1(a, b) a##e##b
#define CON2(a, b) a##b##00
int main()
{printf(%f\n, CON1(8.5, 2));printf(%d\n, CON2(12, 34));return 0;
} 运行结果 850.000000 123400 3.2.5 带副作用的宏参数 当宏参数在宏的定义中出现超过一次的时候如果参数带有副作用那么你在使用这个宏的时候就可能 出现危险导致不可预测的后果。副作用就是表达式求值的时候出现的永久性效果。 3.2.6 宏和函数对比 宏通常被应用于执行简单的运算。比如在两个数中找出较大的一个。 #define MAX(a, b) ((a)(b)?(a):(b)) 那为什么不用函数来完成这个任务 原因有二 1. 用于调用函数和从函数返回的代码可能比实际执行这个小型计算工作所需要的时间更多。 所以宏比函数在程序的规模和速度方面更胜一筹。 2. 更为重要的是函数的参数必须声明为特定的类型。 所以函数只能在类型合适的表达式上使用。反之这个宏怎可以适用于整形、长整型、浮点型等可以 用于来比较的类型。 宏是类型无关的。 宏的缺点当然和函数相比宏也有劣势的地方 1. 每次使用宏的时候一份宏定义的代码将插入到程序中。除非宏比较短否则可能大幅度增加程序 的长度。 2. 宏是没法调试的。 3. 宏由于类型无关也就不够严谨。 4. 宏可能会带来运算符优先级的问题导致程容易出现错。 本质上的区别宏展开仅仅是字符串的替换不会对表达式进行计算宏在编译之前就被处理掉了它没有机会参与编译也不会占用内存。而函数是一段可以重复使用的代码会被编译会给它分配内存每次调用函数就是执行这块内存中的代码。 3.2.7 命名约定 一般来讲函数的宏的使用语法很相似。所以语言本身没法帮我们区分二者。 那我们平时的一个习惯是 把宏名全部大写 函数名不要全部大写 3.3 #undef 这条指令用于移除一个宏定义。 #undef NAME //如果现存的一个名字需要被重新定义那么它的旧名字首先要被移除。 3.4 命令行定义 许多C 的编译器提供了一种能力允许在命令行中定义符号。用于启动编译过程。 例如当我们根据同一个源文件要编译出一个程序的不同版本的时候这个特性有点用处。假定某个 程序中声明了一个某个长度的数组如果机器内存有限我们需要一个很小的数组但是另外一个机器 内存大些我们需要一个数组能够大些。 #include stdio.h
int main()
{int array [ARRAY_SIZE];int i 0;for(i 0; i ARRAY_SIZE; i ){array[i] i;}for(i 0; i ARRAY_SIZE; i ){printf(%d ,array[i]);}printf(\n );return 0;
}
编译指令
//linux 环境演示
gcc -D ARRAY_SIZE10 programe.c 3.5 条件编译 在编译一个程序的时候我们如果要将一条语句一组语句编译或者放弃是很方便的。因为我们有条件编译指令。 比如说 调试性的代码删除可惜保留又碍事所以我们可以选择性的编译。 这些操作都是在预处理阶段完成的多余的代码以及所有的宏都不会参与编译不仅保证了代码的正确性还减小了编译后文件的体积。这种能够根据不同情况编译不同代码、产生不同目标文件的机制称为条件编译。条件编译是预处理程序的功能不是编译器的功能。 常见的条件编译指令 1. 单分支条件编译 #if 整型常量表达式#endif 如进行注释掉#if 0 #endif 2.多分支条件编译 #if 整型常量表达式1 程序段1 #elif 整型常量表达式2 程序段2 #elif 整型常量表达式3 程序段3 #else 程序段4#endif 它的意思是如常“表达式1”的值为真非0就对“程序段1”进行编译否则就计算“表达式2”结果为真的话就对“程序段2”进行编译为假的话就继续往下匹配直到遇到值为真的表达式或者遇到 #else。这一点和 if else 非常类似。 需要注意的是#if 命令要求判断条件为“整型常量表达式”也就是说表达式中不能包含变量而且结果必须是整数而 if 后面的表达式没有限制只要符合语法就行。这是 #if 和 if 的一个重要区别。 3.判断是否被定义 #ifdef 宏名 程序段1 #else 程序段2 #endif 也可以省略 #else #ifdef 宏名 程序段#endif 它的意思是如果当前的宏已被定义过则对“程序段1”进行编译否则对“程序段2”进行编译。 4.判断是否未被定义 #ifndef 宏名 程序段1 #else 程序段2 #endif 与 #ifdef 相比仅仅是将 #ifdef 改为了 #ifndef。它的意思是如果当前的宏未被定义则对“程序段1”进行编译否则对“程序段2”进行编译这与 #ifdef 的功能正好相反。 总结#if、#ifdef、#ifndef的用法区别在哪里 #if 后面跟的是“整型常量表达式”而 #ifdef 和 #ifndef 后面跟的只能是一个宏名不能是其他的。 3.6文件包含
3.6.1头文件被包含的方式 #include叫做文件包含命令用来引入对应的头文件.h文件。#include 也是C语言预处理命令的一种。#include 的处理过程很简单就是将头文件的内容插入到该命令所在的位置从而把头文件和当前源文件连接成一个源文件这与复制粘贴的效果相同。这种替换的方式很简单 预处理器先删除这条指令并用包含文件的内容替换。 这样一个源文件被包含10次那就实际被编译10次。头文件分为两种标准头文件和自己编写的头文件。 #include 的用法有两种 #include stdHeader.h
#include myHeader.h 关于 #include 用法的注意事项 一个 #include 命令只能包含一个头文件多个头文件需要多个 #include 命令。同一个头文件可以被多次引入多次引入的效果和一次引入的效果相同因为头文件在代码层面有防止重复引入的机制。文件包含允许嵌套也就是说在一个被包含的文件中又可以包含另一个文件。 编程习惯习惯是使用尖括号来引入标准头文件使用双引号来引入自定义头文件自己编写的头文件这样一眼就能看出头文件的区别。 3.6.2 嵌套文件包含
如果出现这样的场景 comm.h和comm.c是公共模块。 test1.h和test1.c使用了公共模块。 test2.h和test2.c使用了公共模块。 test.h和test.c使用了test1模块和test2模块。 这样最终程序中就会出现两份comm.h的内容。这样就造成了文件内容的重复。 如何解决这个问题—条件编译 每个头文件的开头写 第一种 #ifndef __TEST_H__ #define __TEST_H__ //头文件的内容 #endif //__TEST_H__ 第二种 #pragma once 就可以避免头文件的重复引入。 四、其他预处理指令 以上便是程序环境和预处理全部内容认真理解消化一定会有极大的收获至此C语言所有理论技术已经全部总结完认真复习消化练习一定会取得不错的效果。可以留下你们点赞、关注、评论您的支持是对我极大的鼓励下期再见 文章转载自: http://www.morning.wgdnd.cn.gov.cn.wgdnd.cn http://www.morning.lxhrq.cn.gov.cn.lxhrq.cn http://www.morning.cklgf.cn.gov.cn.cklgf.cn http://www.morning.thrtt.cn.gov.cn.thrtt.cn http://www.morning.dqkcn.cn.gov.cn.dqkcn.cn http://www.morning.fwrr.cn.gov.cn.fwrr.cn http://www.morning.myhpj.cn.gov.cn.myhpj.cn http://www.morning.wrlff.cn.gov.cn.wrlff.cn http://www.morning.jxjrm.cn.gov.cn.jxjrm.cn http://www.morning.rlxg.cn.gov.cn.rlxg.cn http://www.morning.tqsgt.cn.gov.cn.tqsgt.cn http://www.morning.fppzc.cn.gov.cn.fppzc.cn http://www.morning.lnfkd.cn.gov.cn.lnfkd.cn http://www.morning.dkqbc.cn.gov.cn.dkqbc.cn http://www.morning.rgksz.cn.gov.cn.rgksz.cn http://www.morning.rkjb.cn.gov.cn.rkjb.cn http://www.morning.zlxrg.cn.gov.cn.zlxrg.cn http://www.morning.qykxj.cn.gov.cn.qykxj.cn http://www.morning.shinezoneserver.com.gov.cn.shinezoneserver.com http://www.morning.qnlbb.cn.gov.cn.qnlbb.cn http://www.morning.dpqqg.cn.gov.cn.dpqqg.cn http://www.morning.bzqnp.cn.gov.cn.bzqnp.cn http://www.morning.qyqmj.cn.gov.cn.qyqmj.cn http://www.morning.fbjqq.cn.gov.cn.fbjqq.cn http://www.morning.kkwbw.cn.gov.cn.kkwbw.cn http://www.morning.rqjfm.cn.gov.cn.rqjfm.cn http://www.morning.qrqcr.cn.gov.cn.qrqcr.cn http://www.morning.rzcfg.cn.gov.cn.rzcfg.cn http://www.morning.dfckx.cn.gov.cn.dfckx.cn http://www.morning.jcnmy.cn.gov.cn.jcnmy.cn http://www.morning.xnhnl.cn.gov.cn.xnhnl.cn http://www.morning.hbnwr.cn.gov.cn.hbnwr.cn http://www.morning.cttti.com.gov.cn.cttti.com http://www.morning.qkdcb.cn.gov.cn.qkdcb.cn http://www.morning.qsxxl.cn.gov.cn.qsxxl.cn http://www.morning.tntqr.cn.gov.cn.tntqr.cn http://www.morning.rgdcf.cn.gov.cn.rgdcf.cn http://www.morning.yrycb.cn.gov.cn.yrycb.cn http://www.morning.rjjys.cn.gov.cn.rjjys.cn http://www.morning.mqfw.cn.gov.cn.mqfw.cn http://www.morning.xbmwm.cn.gov.cn.xbmwm.cn http://www.morning.gqcd.cn.gov.cn.gqcd.cn http://www.morning.bjjrtcsl.com.gov.cn.bjjrtcsl.com http://www.morning.mfsjn.cn.gov.cn.mfsjn.cn http://www.morning.sgnxl.cn.gov.cn.sgnxl.cn http://www.morning.jfmyt.cn.gov.cn.jfmyt.cn http://www.morning.kmjbs.cn.gov.cn.kmjbs.cn http://www.morning.qkqhr.cn.gov.cn.qkqhr.cn http://www.morning.qghjc.cn.gov.cn.qghjc.cn http://www.morning.pzbjy.cn.gov.cn.pzbjy.cn http://www.morning.hsjfs.cn.gov.cn.hsjfs.cn http://www.morning.pbzgj.cn.gov.cn.pbzgj.cn http://www.morning.lwsct.cn.gov.cn.lwsct.cn http://www.morning.fyglr.cn.gov.cn.fyglr.cn http://www.morning.qkskm.cn.gov.cn.qkskm.cn http://www.morning.nssjy.cn.gov.cn.nssjy.cn http://www.morning.nqbs.cn.gov.cn.nqbs.cn http://www.morning.jtkfm.cn.gov.cn.jtkfm.cn http://www.morning.wjhpg.cn.gov.cn.wjhpg.cn http://www.morning.jxgyg.cn.gov.cn.jxgyg.cn http://www.morning.iknty.cn.gov.cn.iknty.cn http://www.morning.zhmgcreativeeducation.cn.gov.cn.zhmgcreativeeducation.cn http://www.morning.zypnt.cn.gov.cn.zypnt.cn http://www.morning.wkcl.cn.gov.cn.wkcl.cn http://www.morning.ccsdx.cn.gov.cn.ccsdx.cn http://www.morning.slnz.cn.gov.cn.slnz.cn http://www.morning.cxlys.cn.gov.cn.cxlys.cn http://www.morning.kchwr.cn.gov.cn.kchwr.cn http://www.morning.fwwkr.cn.gov.cn.fwwkr.cn http://www.morning.blfll.cn.gov.cn.blfll.cn http://www.morning.rgnq.cn.gov.cn.rgnq.cn http://www.morning.ykmtz.cn.gov.cn.ykmtz.cn http://www.morning.pqnkg.cn.gov.cn.pqnkg.cn http://www.morning.dlurfdo.cn.gov.cn.dlurfdo.cn http://www.morning.hdnd.cn.gov.cn.hdnd.cn http://www.morning.nrcbx.cn.gov.cn.nrcbx.cn http://www.morning.xckdn.cn.gov.cn.xckdn.cn http://www.morning.dnpft.cn.gov.cn.dnpft.cn http://www.morning.zlces.com.gov.cn.zlces.com http://www.morning.dyxlm.cn.gov.cn.dyxlm.cn