【C语言】程序环境和预处理

目录

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

         二.编译+链接

2.1翻译环境

2.2翻译环境的几个阶段

2.3运行环境

三.预处理

3.1预定义符号

3.2#define

3.3命名约定

3.4#undef

3.5 条件编译


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

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

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

二.编译+链接

2.1翻译环境

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

2.2翻译环境的几个阶段

2.3运行环境

程序执行的过程:

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

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

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

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

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

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

三.预处理

3.1预定义符号

  • 在预处理阶段被处理的已经定义好的符号,可以拿来直接用

   __FILE__       // 代码所在的  源文件,路径
   __LINE__       // 代码所在的  行号
   __DATE__       // 程序被编译的  日期
   __TIME__       // 程序被编译的  时间
   __FUNCTION__   // 代码所在函数的  函数名
  • 左下和右下都是2个下划线

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

例子:


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

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

在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("%d\n",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("%d\n", SQUARE(3));//实现后为 printf("%d\n", 3*3); 
    return 0;
}
//9

释义:

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

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

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

#include <stdio.h>
 
#define SQUARE(X) X*X 
int main() 
{
    printf("%d\n", SQUARE(3+1));
    //实现后为 printf("%d\n", 3+1*3+1); 
    return 0;
}
//7

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

#include <stdio.h>
 
#define SQUARE(X) (X)*(X) 
int main() 
{
    printf("%d\n", SQUARE(3+1));
    return 0;
}
//16

注意下面这种情况:

#include <stdio.h>
 
#define SQUARE(X) (X)+(X) 
int main() 
{
    printf("%d\n", 10 * SQUARE(4));

    return 0;
}
// 实现后是 printf("%d\n", 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 = %d\n", 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("%d\n", 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;
}

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值