C语言进阶(预处理命令详解)

 更新时间:2025年07月25日 15:16:16   作者:大阳123  
文章讲解了宏定义规范、头文件包含方式及条件编译应用,强调带参宏需加括号避免计算错误,头文件应声明函数原型以便主函数调用,条件编译通过宏定义控制代码编译,适用于测试与模块化开发

1.宏定义

1.1不带参宏

#define  PI   3.14

变量名尽量大写

1.2带参宏

定义方式:

#define  MAX(x, y)     x > y ? x : y

下面的代码运行结果为15,显然是错误的。

   #include <stdio.h>
   #define JISUAN(x, y, z)    x * y + z
   int main(void)
   {
       int a = 0;                                                                                                                                                 
       a = JISUAN(1 + 2,2 * 3,3 - 1);
       printf("%d",a);
   }     

给变量带上括号,运行结果是,正确做法如下:运行结果为20。因此尽量给定义添加括号。避免计算错误。

   #include <stdio.h>
   #define JISUAN(x, y, z)    ((x) * (y) + (z))
   int main(void)
   {
       int a = 0;                                                                                                                                                 
       a = JISUAN(1 + 2,2 * 3,3 - 1);
       printf("%d",a);
   }     

带参宏和函数的区别:

带参宏函数
带参宏没有参数类型、返回值、函数类型 相关概念函数有参数类型、函数类型、返回值相关 概念
带参宏只是代码的替换,没有调用传参过 程函数有调用、传参过程
带参宏是在程序编译时展开,代码体积增 大函数是在程序运行过程中加载,代码体积 不会增大
带参宏没有传参过程,执行效率高函数有传参过程,需要调用、传参产生资 源开销
简单的代码想要封装模块,优先带参宏需要严谨的代码逻辑,多行代码,考虑使 用函数

2.头文件的包含

#include <stdio.h>
#include <string.h>
#include <math.h>
#include "head.h"

#include 包含一个文件,文件会在预处理编译时展开。

<>:在系统目录下查找该头文件。

"":在当前目录下查找该头文件,如果找不到再到系统目录下查找头文件。

2.1头文件中的内容

1.构造数据类型的定义

2.全局变量的声明

3.全局函数的声明

4.宏定义

2.2工程结构

main.c中负责主函数编写

  • 功能代码.c中主要负责功能函数的编写
  • 功能代码.h中主要负责声明功能代码.c中编写的功能函数
  • 调用函数的文件只需加对应函数的.h头文件即可使用该函数

这么说可能有些不太好理解,我们来举个例子吧:

我们先创建一个工程文件夹jisuan来进行输入两个数字的四则运算:

再在里面创建jia.c jia.h jian.c jian.h cheng.c cheng.h chu.c chu.h main.c,一个.c的功能文件必须对应一个.h的头文件声明用来方便主文件的调用!这里main.c不需要头文件。因为这里存放主函数。

创建好后分别对jia.cjian.c cheng.c chu.c函数进行编写。

  • jia.c:
   #include<stdio.h>
   float jia(float x , float y)                                                                                                                                                     
         {
             return x + y;
         }
  • jian.c:
  #include <stdio.h>
   float jian(float x , float y)
         {
             return x - y;                                                                                                                                                          
         }
  • cheng.c:
  #include<stdio.h>                                                                                                                                                                
   float cheng(float x , float y)
         {
             return x * y;
         }
  • chu.c:
   #include<stdio.h>
   extern float chu(float x , float y)                                                                                                                                              
         {
             return x / y;
         }

接下来依次编写他们的头文件:

  • jia.h
 extern float jia(float x ,float y); 

jian.h

 extern float jian(float x ,float y); 
  • cheng.h
 extern float cheng(float x ,float y); 
  • chu.h
 extern float chu(float x ,float y); 

最后我们进行主函数的编写:这里要注意一定要用#include"函数功能.h"来声明定义的变量

  • main.c:
   #include<stdio.h>
   #include"jia.h"
   #include"jian.h"
   #include"cheng.h"
   #include"chu.h"
   
   int main(void)
   {
       float r1 = 0;
      float r2 = 0;
      float r3 = 0;
      float r4 = 0;
      float a = 0;
      float b = 0;
      scanf("%f %f",&a,&b);
      r1 = jia(a,b);
      r2 = jian(a,b);
      r3 = cheng(a,b);
      r4 = chu(a,b);
      printf("jia = %f\n",r1);
      printf("jian = %f\n",r2);
      printf("cheng = %f\n",r3);
      printf("chu = %f\n",r4);
      return 0;
  }  

ok,编写工作完成,我们来对.c文件进行编译:

编译完成后就会出现一个可执行文件main

我们试着运行一下:

输入12和45,得出计算结果。

这里,我在想这不是跟我前一篇写的函数里extern外部声明一样的嘛,只不过通过#include""展开函数声明而已。但是在未来的项目中撰写每个功能代码和主函数的不是同一个人,为了方便撰写主函数的人调用,采用这样的方法是不错的选择。

3.条件编译

关键字功能描述
#if如果条件为真则编译后续代码块
#elif若前面的#if或#elif条件不成立,并且该条件成立,则编译该部分的后续代码块
#else若前面的#if和#elif都不成立,则编译该部分代码块
#endif结束一个条件编译块,必须要与#if,#ifdef,#ifndef联用
#ifdef若某个宏被定义,则使用该部分代码
#ifndef若某个宏没被定义,则使用该部分代码
#if 1
编译此部分
#elif 
不编译该部分
#else
#if 0
不编译该部分
#elif 1
编译该部分
#else
test
#if 0
不编译该部分
#elif 0
不编译该部分
#else
编译该部分
#if 1
编译该部分
#endif  结束此条件编译
#if 0
不编译该部分
#endif  结束此条件编译

#ifdef与#ifndef一般在项目测试中使用,可以在编译时于外部定义或不定义某个宏,以此来调用代码。

  #include <stdio.h>
  #define JISUAN(x, y, z)    ((x) * (y) + (z))
  int main(void)
  {
      #ifdef  TEST
      printf("测试\n");
      #endif
      #ifdef  YINGYONG
      printf("应用\n");
      #endif
      return 0;
  } 

如上述代码,对其编译gcc -D TEST l.c -o l 在编译的时候在外部定义了TEST,则输出测试

如果在外部定义YINGYONG 则输出应用。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • VS2013安装配置和使用Boost库教程

    VS2013安装配置和使用Boost库教程

    这篇文章主要为大家详细介绍了VS2013安装配置和使用Boost库的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-04-04
  • 在Visual Studio Code中配置C++编译环境的问题

    在Visual Studio Code中配置C++编译环境的问题

    关于Visual Studio Code对C++环境的配置方法应该有好多种,我这里用到了其中的两种,具体内容详情文中给大家详细介绍,对Visual Studio Code配置C++编译环境相关知识感兴趣的朋友一起看看吧
    2021-07-07
  • C++中CSimpleList的实现与测试实例

    C++中CSimpleList的实现与测试实例

    这篇文章主要介绍了C++中CSimpleList的实现与测试实例,较为详细的讲述了C++列表类的实现方法,需要的朋友可以参考下
    2014-10-10
  • C++带有指针成员的类处理方式详解

    C++带有指针成员的类处理方式详解

    这篇文章主要为大家详细介绍了C++带有指针成员的类处理方式,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-08-08
  • C语言 数据类型详细介绍

    C语言 数据类型详细介绍

    本文主要讲解C语言 数据类型,这里整理了详细的数据类型的资料,希望能帮助刚刚开始学习C语言的同学
    2016-08-08
  • C++函数pyrUp和pyrDown来实现图像金字塔功能

    C++函数pyrUp和pyrDown来实现图像金字塔功能

    这篇文章主要介绍了C++函数pyrUp和pyrDown来实现图像金字塔功能,如何使用OpenCV函数 pyrUp 和 pyrDown 对图像进行向上和向下采样,需要的朋友可以参考下
    2017-03-03
  • C++控制台循环链表实现贪吃蛇

    C++控制台循环链表实现贪吃蛇

    这篇文章主要为大家详细介绍了C++控制台循环链表实现贪吃蛇,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-04-04
  • C++vector自定义大小方式

    C++vector自定义大小方式

    这篇文章主要介绍了C++vector自定义大小方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-05-05
  • 一起聊聊C++中的智能指针

    一起聊聊C++中的智能指针

    C++ 是手工管理内存的分配和释放,这给了程序员极大的自由度也给了我们极高的门槛,弄不好就得内存泄露。使用智能指针能更好的管理堆内存,本文主要给大家介绍一下c++的智能指针,需要的朋友可以参考下
    2022-07-07
  • Qt中鼠标点击的几种状态

    Qt中鼠标点击的几种状态

    在Qt中,鼠标点击按钮通常会触发一系列的事件,包括pressed、released、clicked等,本文主要介绍了Qt中鼠标点击的几种状态,具有一定的参考价值,感兴趣的可以了解一下
    2023-12-12

最新评论