[C/C++] 预处理

7 篇文章 0 订阅

1程序的翻译与执行环境

执行是涉及硬件的,不是这系列的重点

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WzKtik58-1650299934428)(figs/2.png)]

  • 编译部分是将源文件xxx.c通过编译器编译成xxx.obj
  • 链接部分是将xxx.obj+链接库放到链接器中链接成可执行程序

在这里插入图片描述
在这里插入图片描述

  • 在汇编阶段,把各个文件的全局符号生成对应的符号表xxx.o;在链接阶段,把各个符号表进行汇总,如果发现有无法解析的函数地址,则出现错误

2预处理!

2.1预定符号

  • 这些是内置好的符号
  • __FILE__;当前编译源文件的路径
  • __LINE__;该代码当前所在的行号
  • __DATE__;当前日期
  • __TIME__;当前时间
  • __FUNCTION__;当前的所在的函数名
  • __LINE__;
  • 以上通常是为了写log用的

2.2#define

  • #define M 100
  • #define reg register
  • #define do_forever for(…;…;…)
  • #define CASE break;case
  • 就是可以自己定义一段东西,在预处理时直接替换
  • 加;就是会在预处理时加上分号,所以要斟酌使用

2.3#define 定义宏

  • #define SQUARE(X) X*X

宏的一个缺陷

由于宏#define是一个预编译的操作,相关的运算并不是在预编译中进行的,所以会出现如下情况

#define SQUARE(X) X*X
//#define SQUARE(X) ((X)*(X))//如果想要3*3的效果,得这么改,括号不能省
#include<iostream>
using namespace std;

int main()
{
    cout<<SQUARE(1+2);//由于是完全替换,到时候上面语句在预编译时会转化成:1+2*1+2 =5
    return 0;
}

2.4#(非define哪个)和##

  • 将#x的内容替换成对应的字符串(而非变量值)

  • 只能在宏中使用

#define PRINT(X,F) printf("the value of  "#X" is "F,X);

int main()
{
    int a  =10;
    PRINT(a,"%d");
    int b = 20;
    PRINT(b,"%d");

    float f = 2.5f;
    PRINT(f,"%f");
    return 0;
}

##的使用

  • 把两个字符串合在一起

2.5带副作用的宏参数

主要出现在a++,++a这种,因为他是完全替换。这是一种危险的编程行为。

2.6宏和函数的对比

宏的优势

  • 宏:直接在预处理阶段完全替换,所需要的的汇编代码是更少的。他跟inline很像,但是inline实在编译期间展开的,且本质时函数。
  • 函数:需要做相当多的准备工作,编译,才能进行核心的汇编代码。
  • 如果调用+返回的过程比实际执行小型计算时更长,应该用宏。
  • 此外,函数需要明确的类型,而宏允许其他类型,此时宏更为灵活,如:
      #define MAX(X,Y) ((X)>(Y)?(X):(Y))
    
      int Max(int x,int y)
      {
          return x>y?x:y;
      }
    

宏的劣势

  • 由于是完全替换,即实际上会插入到程序中。因此一般建议宏是一个小巧的功能。而函数不是,函数是专门开辟了一片内存空间的,使用时就去那片空间找。
  • 宏没办法debug!因为调试是在代码编译,链接后形成.exe时才能debug,而宏在预处理阶段已经全部替换了。
  • 宏由于没有明确类型定义,缺乏严谨性
  • 括号少括了,操作符的优先级,会导致未知错误
  • 宏不允许递归

2.7#undef

取消一个定义

2.8条件编译,跟条件判断类似,预处理时跟注释类似

  1. #define PRINT
     int main()
     {
         //如果PRINT定义了就编译
     #ifdef PRINT
         printf("1");
     #endif
         return 0;
     }
    
  2. #if
    
    #elif
    
    #else
    
    #endif
    
  3.  //如果HEHE不定义,下面参与编译
     #ifndef HEHE
     #endif
    
  4. 允许嵌套
     #if defined(OS_UNIX)
         #ifdef OPTION1
             unix_version_option1();
         #endif
     #endif
    

2.9文件包含

  • 自己定义的头文件用#include “add.h”,来引入。称为本地文件的包含。他会在本地位置查找,如果找不到则去库函数的头文件目录下找

  • #include <stdio.h>,为库文件的包含。<>直接去库函数里面找。

  • 防止头文件被重复包含用
    :
    第一种:#pragma once

    第二种:

    #ifndef __TEST_H__

    #define __TEST_H__

    #endif

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值