C语言程序环境和预处理(一)

简介: C语言程序环境和预处理

1.翻译环境和执行环境


在 ANSIC标准中,程序实现存在两个不同的环境


翻译环境,源代码被转换为可执行的机器指令
执行环境,用于实际执行代码


2.编译+链接


2.1翻译环境


962d6c2a049d247407d8365df67e743b_3c67865b5b814bbfbce50fecdf7d6107.png


1.组成一个程序的每个源文件通过编译过程分别转化为目标代码
2.每个目标文件由链接器捆绑在一起,形成单一且完整的可执行程序
3.链接器同时也会引入标准C函数库中任何被该程序所用到的函数


2.2编译


2.3运行环境


程序执行过程


程序必须载入内存中,在由操作系统的环境中:一般由操作系统完成,在独立的环境中,程序的载入需由手工安排,也可能通过可执行代码置入只读内存来完成

程序的执行开始后,接着调用mian函数

开始执行程序代码,程序将会使用一个运行堆栈,存储函数的局部变量和返回地址。程序同时也可以使用静态内存,存储于静态内存中的变量在程序的整个执行过程一直保留其值

终止程序,正常终止main函数,也存在意外终止


3.预处理


3.1预定义符号


__FILE__    进行编译的源文件
__LINE__    文件当前的行号
__DATE__    文件被编译的日期
__TIME__    文件被编译的时间
__STDC__    如果编译器遵循ANSIC标准,其值为 1


实例


int main()
{
  printf("%s\n", __FILE__);
  return 0;
}


f5946af2ed12226c8f273698400ea254_98364c6da64c465cb498460b6c73392a.png


3.2#define


3.2.1#define定义标识符


#define name stuff


实例


#define ROW 10
#define COL 10
#define reg register  为register,创建一个简短的名字


在define定义标识符时,在最后不要加上;,主要思想是替换


3.2.2#define定义宏


#define机制包括一个规定,允许把参数替换到文本中,
这种实现通常称为宏或者定义宏


宏的申明方式:

#define name(parament-list)stuff

parament-list是由逗号隔开的符号表


参数列表的左括号必须与name紧邻

如果两者之间有任何空白存在,参数列表就会被解释为stuff的一部分


实例


#include<stdio.h>
#define SQUARE(x) x*x
int main()
{
  printf("%d\n", SQUARE(5));
  return 0;
}

5d14a67a3740eaa51f823c157840d8cc_1312cbd504e24f5bb651d73422033dfd.png


提示


用于对数值表达式进行求值的宏定义都应该用加上括号这种方式,
避免在使用宏时由于参数中的操作或临近操作符之间不可预料的相互作用


3.2.3#define替换规则


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

替换文本随后被插入到程序中原来文本的位置。宏,参数名被其值所替换

最后,再次对结果文本进行扫描,观察是否包含任何由#define定义的符号。如果包含,则重复上述操作


1.宏参数和#define定义中可以出现其他#define定义的符号,但是对于宏,不能出现递归

2.当预处理器搜索#define定义的符号时,字符串常量的内容不被搜索


3.2.4#和##


int main()
{
  printf("hello ""crush");
  return 0;
}


5173319f4d94b27a9521c77ec124c21b_b4fadb0f4a5347ebb3091e5e5fa867de.png


从上面的代码可以发现,字符串有自动连接的特点


如果字符串中存在宏参数该如何自动链接呢


#,可以把宏参数变成对应的字符串


代码实现如下


#include<stdio.h>
#define PRINT(N) printf("the value of "#N" is %d\n",N)
int main()
{
  int i = 5;
  PRINT(i);
  printf("the value of ""i"" is %d\n", i);
  return 0;
}


13d64bcac6e47bf0bf396840f69a5031_4e7729051a124b56a3fc9d6a6dd9f095.png


由运行结果可以说明,#的作用:把一个宏参数变成对应的字符串


##的作用


##可以把位于其两边的符号合成一个符号
允许宏定义从分离的文本片段创建标识符


代码实现


#include<stdio.h>
#define SUM(hello,crush) hello##crush
int main()
{
  int hellocrush = 123;
  printf("%d\n", SUM(hello, crush));
  return 0;
}


41a4de4389c3fe3ede7c25a973619baf_bf746a7dc2104791bce601017ff673ca.png


3.2.5含有副作用的宏参数


当宏参数在宏定义中出现超过一次时,如果参数带有副作用,在使用宏时就会出现问题,导致不可预测的后果。副作用就是表示式求值时出现的永久性效果。

例如


x+1  没有副作用
x++  带有副作用


观察下列代码及运行结果


#define MAX(a,b) ((a>b)?(a):(b))
int main()
{
  int a = 2;
  int b = 3;
  int c = MAX(a++, b++);
  //c=((a++>b++)?(a++):(b++))
  printf("a=%d b=%d c=%d\n", a, b, c);
  return 0;
}


9ed49431ee9f6bde630ad528386e7d5d_daa75b89024a4a70a11f1c2feffe91fc.png


后置加加带有的副作用,使运行结果出乎意料,所以应尽量避免使用带有副作用的宏参数


3.2.6宏和函数


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


宏与函数相比


优点


用于调用函数和从函数返回的代码可能比实际执行程序需要的时间更多,所以宏比函数在程序的规模和速度方面更胜一筹


函数的参数必须声明为特定的类型

故函数只能在类型合适的表达式上使用,相反宏可以适用任何类型的数据进行比较

宏的类型是任意的

缺点


每次使用宏时,都需要将宏定义的代码插入程序中,如果宏比较长,可能大幅度增加程序的长度反而降低程序的可读性

宏不能进行调试,因为宏是被替换的


宏由于类型任意,也就不够严谨


宏可能会带来运算符优先级的问题,导致程序出现错误


3.2.7命名约定


一般情况下,函数和宏的使用语法类似,故语言本身没办法区分二者

所以有一个习惯


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

目录
相关文章
|
5天前
|
C语言
第一章 C语言知识点(程序)
第一章 C语言知识点(程序)
16 0
|
3天前
|
编译器 C语言
C语言:预处理
C语言:预处理
7 1
C语言:预处理
|
4天前
|
存储 自然语言处理 编译器
“ Hello world ”中的秘密之【C语言程序编译和链接】
作为C语言最经典的代码,大家都可以轻易写出。但是代码的运行过程却很少有人清楚,接下来我将介绍代码运行的奥秘。
15 0
|
6天前
|
自然语言处理 编译器 C语言
C语言程序编译和链接
在ANSI C的任何⼀种实现中,存在两个不同的环境。 第1种是翻译环境,在这个环境中源代码被转换为可执⾏的机器指令(⼆进制指令)。 第2种是执⾏环境,它⽤于实际执⾏代码。
|
8天前
|
网络协议 物联网 数据处理
【C 言专栏】C 语言实现网络通信程序
【5月更文挑战第4天】本文探讨了使用C语言实现网络通信程序的方法,包括理解网络通信基本概念如协议和套接字,以及TCP/UDP通信的实现步骤。通过创建套接字、绑定端口、监听连接、数据传输和错误处理等关键环节,阐述了C语言在网络通信中的优势。文中还提到了实际应用案例、程序优化策略及未来发展趋势,旨在帮助读者掌握C语言在网络通信领域的应用技巧。
【C 言专栏】C 语言实现网络通信程序
|
11天前
|
并行计算 算法 测试技术
【C 言专栏】优化 C 语言程序性能的策略
【5月更文挑战第2天】本文探讨了优化C语言程序性能的策略,包括算法优化(选择合适的时间和空间复杂度)、代码结构优化(减少函数调用,合理使用循环)、内存管理优化(合理分配和及时释放内存)、编译器优化(选择优化级别,内联函数,循环展开)、数据结构优化(根据需求选择数组、哈希表或堆)、并行计算优化(多线程、多进程和MPI编程)以及性能测试与分析(使用性能分析工具、基准测试和分析执行路径)。通过这些方法,可以提升C语言程序的效率和运行速度。
|
12天前
|
存储 Linux C语言
C语言进阶第十一节 --------程序环境和预处理(包含宏的解释)-2
C语言进阶第十一节 --------程序环境和预处理(包含宏的解释)
|
18天前
|
C语言
C语言:内存函数(memcpy memmove memset memcmp使用)
C语言:内存函数(memcpy memmove memset memcmp使用)