技术学习分享_CKX技术 技术资讯 C语言——程序环境和预处理

C语言——程序环境和预处理

广告位
  • 程序的翻译环境和执行环境
  • 编译+链接
  • 预处理

一.程序的翻译环境和执行环境

ANSI C标准的任何一种实现中,存在两种不同的环境:

  1. 翻译环境:该环境中 源代码 会被转换为 可执行的机器指令
  2.  执行环境:其用于实际 执行代码

C语言——程序环境和预处理

二.编译+链接

2.1翻译环境

C语言——程序环境和预处理

  • 一个源文件经过编译器处理形成一个目标文件,目标文件被链接器链接形成可执行程序
  • 翻译环境是 编译 和 链接

2.2翻译环境的几个阶段

C语言——程序环境和预处理

2.3运行环境

程序执行的过程:

  1. 程序必须载入内存中。

           在有操作系统的环境中:程序的载入一般由操作系统完成。

           在独立环境中:程序的载入必须手工安排,也可能是通过可执行代码置入只读内存来完成。

2.程序的执行便开始。接着便调用 main 函数。

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

4.终止程序。正常终止main函数,也可能是意外终止

三.预处理

3.1预定义符号

  • 在预处理阶段被处理的已经定义好的符号,可以拿来直接用
   __FILE__       // 代码所在的  源文件,路径
__LINE__ // 代码所在的 行号
__DATE__ // 程序被编译的 日期
__TIME__ // 程序被编译的 时间
__FUNCTION__ // 代码所在函数的 函数名
  • 左下和右下都是2个下划线

C语言——程序环境和预处理

  • 如果一个工程特别复杂,这时去调试时可能会无从下手。所以需要代码在运行的过程中记录一些日志信息,即可通过日志信息看程序哪里出了问题

例子:

#include <stdio.h> 
int main()
{
int i = 0;
FILE* pf = fopen("acc.txt", "a+");
if (pf == NULL)
{
perror("fopenn");
return 1;
}
for (i = 0; i < 10; i++)
{
fprintf(pf,"%s %d %s %dn",__FILE__, __LINE__, __DATE__,__TIME__ );
}
fclose(pf);
pf = NULL;
return 0;
}

C语言——程序环境和预处理

  • 除以上5个外,还有一个 __STDC__如果编译器遵循 ANSI C 标准则返回1,否则未定义

C语言——程序环境和预处理

在Dev-c++上有1,表明其遵循 ANSI C 标准

3.2#define

3.2.1 #define 定义标识符

语法:​

#define name  stuff

//例子:
//#define MAX 100
//#define reg register

注意:#define 定义标识符 ,其末尾不用再加个分号

例子:

#include <stdio.h> 
#define M 100
//预处理阶段就会将M替换成100
int main()
{
int m = M;
printf("%dn",m);
return 0;
}
//100

3.2.2  #define 定义宏

  • #define 机制有个规定,允许把参数替换到文本中,这种实现成为宏或定义宏

申明方式:

#define name( parament-list ) stuff

//name和左括号必须紧紧在一起,否则后面的参数会被当成stuff的一部分

举例:

#include <stdio.h>

#define SQUARE(X) X*X
int main()
{
printf("%dn", SQUARE(3));//实现后为 printf("%dn", 3*3);
return 0;
}
//9

// 先将函数中name()中的参数替换 掉宏中的参数,再将stuff的结果返回函数去 替换掉name()

特别注意宏的参数是完全替换的,不事先计算再传参

例子:用类似上述方法得出16


#include <stdio.h>

#define SQUARE(X) X*X
int main()
{
printf("%dn", SQUARE(3+1));
//实现后为 printf("%dn", 3+1*3+1);
return 0;
}
//7

//这样明显不对,So在敲的时候我们可以带上()来防止出错

#include <stdio.h>

#define SQUARE(X) (X)*(X)
int main()
{
printf("%dn", SQUARE(3+1));
return 0;
}
//16

注意下面这种情况:

#include <stdio.h>

#define SQUARE(X) (X)+(X)
int main()
{
printf("%dn", 10 * SQUARE(4));

return 0;
}
// 实现后是 printf("%dn", 10 * (4) + (4));
//所以结果是44

3.2.3  #define 替换规则

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

  1. 在调用时,首先对参数进行检查,看是否包含任何由 #define 定义的符号。如果是,它们先被替换
  2. 替换文本随后被插入到程序中原来的文本位置。对于宏,函数名被它们的值替换
  3. 再次对结果文件进行扫描,看是否包含任何由 #define 定义的符号。如果包含,就重复上述过程。

注意:

  1.  宏参数  #define 定义中可以出现其他 #define 定义的常量。但对于宏,不能出现递归
  2. 当预处理器 搜索 #define 定义的符号的时候,字符串常量中的内容不被搜索,即不会被替换
#include <stdio.h>

#define M 100
int main()
{
printf("M = %dn", M);//前面的M不会被替换
return 0;
}
//100

3.3命名约定

由于一般来讲,函数和宏的使用语法相似,所以为了区分它们,用一个习惯是:宏名全部大写,函数名不要全部大写

3.4#undef

该命令用于 移除一个宏定义

语法格式:

#undef NAME

例子:

#include <stdio.h>

#define M 100
int main()
{
int a = M;
#undef M
printf("%dn", M);

return 0;
}

3.5 条件编译

在编译一个程序时,可以用条件编译将一条语句或一组语句编译/放弃是很方便的

#include <stdio.h>

#define __DEBUG__
int main()
{
int arr[10] = {0};
int i = 0;
for (i = 0; i < 10; i++)
{
arr[i] = i;
#ifdef __DEBUG__
printf("%d ", arr[i]);//如果定义了则会编译 ,没有定义则不会参与编译
#endif
}
return 0;
}

//如果定义了则会编译 ,没有定义则不会参与编译

本文来自网络,不代表技术学习分享_CKX技术立场,转载请注明出处。

作者: CKX技术

上一篇
下一篇
广告位

发表回复

返回顶部