目录
前言
大家好,本文篇文章主要是简单讲解一下C语言中的程序环境,以及一些预处理命令
一、程序的翻译环境和执行环境
翻译环境:在这个环境中源代码被转换为可执行的机器指令。
执行环境:用于实际执行代码。
二、编译链接
1.翻译环境
一个源程序需要编译加链接才能转换为可执行程序,然后编译又可以分为预编译(预处理)、编译和汇编
2.运行环境
程序执行的过程:
1. 程序必须载入内存中。在有操作系统的环境中:一般这个由操作系统完成。在独立的环境中,程序的载入必须由手工安排,也可能是通过可执行代码置入只读内存来完成。
2. 程序的执行便开始。接着便调用main函数。
3. 开始执行程序代码。这个时候程序将使用一个运行时堆栈(stack),存储函数的局部变量和返回
地址。程序同时也可以使用静态(static)内存,存储于静态内存中的变量在程序的整个执行过程一直保留他们的值。
4. 终止程序。正常终止main函数;也有可能是意外终止。
三、预处理命令
1.预处理符号
__FILE__ //进行编译的源文件
__LINE__ //文件当前的行号
__DATE__ //文件被编译的日期
__TIME__ //文件被编译的时间
__STDC__ //如果编译器遵循ANSI C,其值为1,否则未定义
这些预定义符号都是语言内置的,我们可以直接使用。
2.#define
(1)#define定义标识符
语法: #define name stuff
举例:
#define MAX 1000 //相当于MAX=1000
#define reg register //为 register这个关键字,创建一个简短的名字
注意:在定义标识符时结尾最好不要加上; 可能会出现一些不必要的错误
(2)#define定义宏
#define 机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)或定义 宏(define macro)。
语法:#define name( 参数 ) 内容
注意: 参数列表的左括号必须与name紧邻。
如果两者之间有任何空白存在,参数列表就会被解释为内容的一部分。
如:#define MUL( x ) x * x
当你声明之后使用的时候MUL(5)
置与程序,预处理器会用下面的表达式替换上面的表达式 5*5
但是使用宏定义的时候一个不注意可能就会造成错误。
例如:
int a = 5; printf("%d\MUL( a + 1) );
替换文本时,参数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));
但是替换之后和预期有一点区别
printf ("%d\n",10 * (5) + (5));
这个问题的解决方法是在宏定义表达式两边再加上一个括号就行了
#define DOUBLE( x) ( ( x ) + ( x ) )
注意:所以用于对数值表达式进行求值的宏定义都应该用这种方式加上括号,避免在使用宏时由于参数中 的操作符或邻近操作符之间不可预料的相互作用。
(3)#define的替换规则
在程序中扩展#define定义符号和宏时,需要涉及几个步骤。
1. 在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,它们首先被替换。
2. 替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值所替换。
3. 最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上述处理过程。
注意:
1. 宏参数和#define 定义中可以出现其他#define定义的符号。但是对于宏,不能出现递归。 2. 当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索。
(4)宏和函数的对比
属性 | #define定义的宏 | 函数 |
代码长度 | 每次使用,宏代码都会被插入到程序中。 | 函数代码只出现于一个地方 |
执行速度 | 更快 | 存在函数的调用和返回,较慢 |
操作符优先级 | 宏参数的求职时在所有周围表达式的上下文的环境里,除非加上括号,否则会出现一些不可预料的后果 | 函数参数只在函数调用的时候求值一次,他的结果值传给函数,表达式结果更容易预测 |
带有副作用的参数 | 蚕食可能被替换到宏体的多个位置,所有带有副作用的参数就职可能会产生不可预料到结果 | 函数参数值在传参的时候求值一次,结果更容易空置 |
参数类型 | 宏的参数与类型无关 | 函数参数时与类型有关的,如果参数类型不同,就属于不同的函数 |
调试 | 宏不方便调试 | 函数是可以逐语句调试的 |
递归 | 宏不能递归 | 函数时可以递归的 |
(5)命名约定
把宏名全部大写
函数名不要全部大写
3.#undef
这条指令用于移除一个宏定义
#undef NAME
//如果现存的一个名字需要被重新定义,那么它的旧名字首先要被移除。
4.条件编译
当我们在写程序调试时,调试性的代码,删除可惜,保留又碍事,所以我们这个时候可以选择性的编译。
#if 如果条件为真,则执行相应操作
#elif 如果前面条件为假,而该条件为真,则执行相应操作
#else 如果前面条件均为假,则执行相应操作
#endif 结束相应的条件编译指令
#ifdef 如果该宏已定义,则执行相应操作
#ifndef 如果该宏没有定义,则执行相应操作
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 OPTION1
unix_version_option1();
#endif
#ifdef OPTION2
unix_version_option2();
#endif
#elif defined(OS_MSDOS)
#ifdef OPTION2
msdos_version_option2();
#endif
#endif
总结
以上就是今天要讲的内容,本文仅仅简单介绍了C语言程序环境与预处理命令的使用,而知晓程序环境和熟练使用预处理命令能够使我们的程序快捷并且美观。
谢谢大家的阅览,欢迎文章存在问题欢迎大家提出以便博主及时改正
文章内容存在借鉴若有侵权请联系删除!!!