程序环境和预处理

程序环境和预处理

1.程序的环境

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

2.翻译环境

组成一个程序的每个源文件通过编译过程分别转换成目标代码。
每个目标文件由链接器捆绑在一起,形成一个单一而完整的可执行程序。
链接器同时也会引入标准C函数库中任何被该程序所用到的函数,而且它可以搜索程序员个人的程序库,将其需要的函数也链接到程序中。

image-20230721190527471

2.1翻译环境四阶段

预编译阶段编译汇编连接
内容预处理指令语法分析、词法分析、语义分析、符号汇总形成符号表、将汇编指令变成二进制指令合并段表、符号表的合并和符号表的重定位
test.ctest.c->test.itest.i->test.stest.s->test.o

3.执行环境

程序执行的过程:

1.程序必须载入内存中

在有操作系统的环境中,一般由操作系统完成。在独立的环境中,程序的载入必须手工安排。

2.程序执行开始

调用main函数。

3.开始执行程序代码

此时程序使用一个运行堆栈,存储函数的局部变量和返回地址。同时程序也使用静态内存,存储在静态内存中的变量在整个执行过程中一直保留他们的值。

4.程序终止

正常终止main函数;也可能是意外终止。

4.预处理详细解析

4.1预定义符号

__FILE__//进行编译的源文件
__LINE__//文件当前的行号
__DATE__//文件被编译的日期
__TIME__//文件被编译的时间
__STDC__  //如果编译器遵循ANSIC,其值为1,否则未定义
  //例子:
  int main()
{
  printf("%d\n",__FILE__,__LINE__);
  return 0;
}

image-20230722140335428

4.2#define

4.2.1#define 定义标识符
#define MAX 100//在程序中用MAX代替100,当我们想修改数字时,就不需要到程序中去一个个找,只需要在此处改变
#define reg register //为register这个关键字创建一个更简短的名字
4.2.2#define 定义宏

允许把参数替换到文本中

#define name(parament-list) stuff
#define SQUARE(x) (x)*(x)
//注意:参数列表的左括号必须与name紧邻
//如果x未知数本身就有加减等运算,会和宏定义中的操作符产生冲突。为了避免这种情况,要对用数值表达式求值的宏定义加上括号
4.2.3 #define 替换规则

在程序中扩展#define定义符号和宏时,有三个步骤:

1.在调用宏时,首先对参数进行检查,看看是否包含#define定义的符号,如果包含,它们首先被替换。

2.替换文本随后被插入到程序中原本到文本的位置。

3.最后,再次对结果文件进行扫描,看看是否包含#define定义的符号,如果有就重复上述过程。

注意:#define定义标识符和宏可以出现其他#define定义的符号,宏不能递归。当预处理器搜索#define定义的符号时,字符串常量的内容不被搜索。

4.2.4 #和##

字符串有自动连接的特点。

#value - "value"
//##把位于它两边的符号合成一个符号
4.2.5带副作用的宏参数
x+1//不带副作用
x++//带有副作用
4.2.6宏和函数的对比
属性#define定义宏函数
代码长度每次使用都将宏代码插入到程序中,程序长度大大增加函数代码只存在一个地方,每次使用函数,调用这个地方的同一份代码
执行速度更快存在函数的调用和返回的开销,相对慢一些
带有副作用的参数参数可能被替换到程序中多个位置,带有副作用的参数求值可能会产生不好的结果函数参数只在传参的时候求值一次,结果易控制
递归不能
参数类型宏的参数和类型无关与类型有关
调试不方便调试可以逐语句调试
4.2.7命名约定

宏名全部大写,函数名不要全部大写

4.3#undef

//这条指令用于移除一个宏定义
#undef NAME

4.4条件编译

//常见的条件编译指令
1.
  #if 常量表达式
  //...
  #endif
2.多个分支的条件编译
  #if 常量表达式
  //...
  #elif 常量表达式
  //...
  #else
  //...
  #endif
3.判断是否被定义
  #if defined(symbol)
  #ifdef symbol
  
  #if !defined(symbol)
  #ifndef symbol  

4.5头文件包含方式

1.本地文件包含

#include "filename"

2.库文件包含

#include <filename.h>

3.嵌套头文件包含

为了避免头文件的重复引用,有以下两种方式:

1.
  #pragma once
2.
  #ifndef __TEST_H__
  #define __TEST_H__
  //头文件的内容
  #endif
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值