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 则输出应用。

总结

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

相关文章

  • Sersync+Rsync实现触发式文件同步实战过程

    Sersync+Rsync实现触发式文件同步实战过程

    sersync是使用c++编写,而且对linux系统文 件系统产生的临时文件和重复的文件操作进行过滤。下面通过本文给大家分享Sersync+Rsync实现触发式文件同步实战过程,需要的朋友参考下吧
    2017-09-09
  • 使用c++实现OpenCV图像横向&纵向拼接

    使用c++实现OpenCV图像横向&纵向拼接

    这篇文章主要介绍了使用c++实现OpenCV图像横向&纵向拼接,文中有图像拼接函数,可以实现如“长图拼接王”这类小程序的类似功能,大家可以将该函数封装在软件中自由使用
    2021-08-08
  • C语言完数的实现示例

    C语言完数的实现示例

    C语言中的完数指的是一个正整数,本文主要介绍了C语言完数,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-05-05
  • c语言尾队列tailq使用示例分享

    c语言尾队列tailq使用示例分享

    这篇文章主要介绍了c语言尾队列tailq使用示例,大家参考使用吧
    2014-01-01
  • C++提取文件名与提取XML文件的方法详解

    C++提取文件名与提取XML文件的方法详解

    这篇文章主要为大家详细介绍了C++提取文件名与提取XML文件的方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助<BR>
    2022-03-03
  • C++中指针和引用的区别详解

    C++中指针和引用的区别详解

    这篇文章主要介绍了C++中指针和引用的区别详解的相关资料,需要的朋友可以参考下
    2017-02-02
  • C++ 泛型编程详解

    C++ 泛型编程详解

    这一篇介绍一下 C++ 编程中与面向对象并列的另一大分支——泛型编程,这一篇主要介绍函数模板、类模板和成员模板三大部分,需要的朋友可以参考下
    2020-02-02
  • Qt4和Qt5的信号和槽的使用区别

    Qt4和Qt5的信号和槽的使用区别

    本文主要介绍了Qt4 和 Qt5 的信号和槽的连接 connect 与断开 disconnect 区别,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-06-06
  • C++11中的可变参数模板/lambda表达式

    C++11中的可变参数模板/lambda表达式

    C++11的新特性可变参数模板能够让我们创建可以接受可变参数的函数模板和类模板,相比C++98和C++03,类模板和函数模板中只能含固定数量的模板参数,可变参数模板无疑是一个巨大的改进,这篇文章主要介绍了C++11中的可变参数模板/lambda表达式,需要的朋友可以参考下
    2023-03-03
  • C/C++中的静态变量注意事项

    C/C++中的静态变量注意事项

    本文主要介绍了C/C++中的静态变量注意事项,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-07-07

最新评论