c语言与预处理指令

本文介绍了C语言的预处理指令,包括系统文件与自定义文件的引用、宏定义的使用及其注意事项,如带参数的宏定义应如何避免错误。还讨论了条件编译和#include指令,解释了条件编译的条件以及头文件的嵌套包含可能导致的问题,提出了防止头文件重复包含的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

预处理指令:在程序编译前执行,效率高,以符号#开头,没有';'结尾的编译指令,这些指令称为预处理命令,预处理命令属于C语言编译器,而不是C语言的组成部分,通过预处理命令可扩展C语言程序设计的环境,

例:

#include <stdio.h>

#include “stu.h”

#include <string.h>

系统文件用<>,自己写的用””

 

宏定义

文件包含

条件编译

定义常量

 

 

 

宏定义不仅在编译前执行,效率比较高,并且不会检测内存,如果替换之后会发生检测

#include <stdio.h>

#include "stu.h"

#include <string.h>

#define LENGTH 20 //length叫宏名,20为被宏名替换的字符串

int main(int argc, const char * argv[])

{

for (int i=0; i<LENGTH; i++) {

        printf("%i\n",i);

    }

    return 0;

}

 

在编译之前会检查所有的LENGTH并把它替换为20

带参数的宏定义注意点,宏定义的参数只做替换操作并不会做计算操作

#include <stdio.h>

#include "stu.h"

#include <string.h>

#define calcSum(a,b) a*b

int main(int argc, const char * argv[])

{

int i=calcSum(2+2,3+6);  

替换过程

// calcSum(a,b) a*b

// int i=a+b; int i=2+2*3+6

return 0;

}

所以宏定义的计算过程定义应该用括号就要采取以下定义方式

 

#include <stdio.h>

#include "stu.h"

#include <string.h>

#define calcSum(a,b) (a)*(b)

int main(int argc, const char * argv[])

{

int i=calcSum(2+2,3+6);  

替换过程

// calcSum(a,b) a*b

// int i=a+b; int i=2+2*3+6

int k=calcSum(2+2,3)/calcSum(1, 2);

//int k=2+2*3/1*2

return 0;

}

 

但是这种定义方式还是不完美存在某些bug,所以我们应该把计算结果也用括号包住,总之我们要记住因为它只是很笨拙的做了替换操作,所以我们在使用宏定义的时候要特别小心

#define calcSum(a,b) ((a)*(b)) //最终正确定义

 

条件编译由宏定义配合,条件中不能放变量,因为变量是程序运行时才会有,而条件编译是在程序编译之前运行

#include <stdio.h>

#include "stu.h"

#include <string.h>

#define LENGTH 20

int main(int argc, const char * argv[])

{

    int k=0;

    #if LENGTH>10

    k=sum(10, 20);

    #elif LENGTH=20

    k=sumAndMin(15, 15, &k);

    #else

    k=sumNum(2, 5);

    #endif

 

    printf("%i",k);

    return 0;

}

程序性能比普通函数中的if else条件判断提高,因为以上条件编译只会编译一行代码

注意:结尾一定要写#endif因为如果没有#endif标记条件编译结束,它会一直编译到程序结尾,这样就会编译不通过,很像sqlthen else

 

是否定义宏定义作为条件编译的条件

#if defined(LENGTH)

        printf("定义了宏名为LENGTH的宏定义");

#endif

   

#if !defined(LENGTH)

    printf("没有定义了宏名为LENGTH的宏定义");

#endif

上面的判断也可以用下面的方式

#ifdef LENGTH

    printf("定义了宏名为LENGTH的宏定义");

#endif

 

#ifndef LENGTH

    printf("没有定义了宏名为LENGTH的宏定义");

#endif

Inlcude指令很像JSP中的inclue,直接把包含文件中的内容拷贝过来,我们经常会再Java项目中定义一些公共的JS文件或者我们自己开发的公共组件用include包含进来

#include <文件名>

在C语言函数头文件所在目录中找

#include "文件名"

先在程序源程序的目录中找,如果找不到,会去path(也就是系统环境变量配置的path)路径找,如果还是找不到才会去C语言函数头文件所在目录中找

可以嵌套包含,a.h包含b.h,b.h包含c.h,但是不可以递归相互包含a.h包含b.h,b.h包含a.h。

因为头文件可以嵌套包含,所以也带来了一些问题,比如头文件重复包含,这个时候我们就要使用宏定义来处理,这也是我们在XCODE中创建头文件的时候,XCODE会自动生成一段宏定义代码的原因,降低重复编译,提高效率

#ifndef testc_Student_h  //如果没有定义宏testc_Student_h

#define testc_Student_h  //定义一个宏testc_Student_h

void test();

#endif

这样不管我们的头文件被包含多少次,但是程序只会编译一次头文件中的代码

### C语言预处理指令种类 C语言中的预处理指令是在编译之前由预处理器执行的命令,这些指令以`#`开头。以下是C语言中常见的预处理指令及其功能说明[^1]: - **`#define`**:用于宏定义,可以定义常量或函数宏。 ```c #define PI 3.14159 ``` 此外,还可以定义带参数的宏[^2]: ```c #define SQUARE(x) ((x) * (x)) ``` - **`#undef`**:用于取消已定义的宏。 ```c #undef PI ``` - **`#include`**:用于包含其他文件的内容,通常用于包含头文件。 ```c #include <stdio.h> #include "myheader.h" ``` - **`#if`**:根据条件判断是否编译某段代码。如果条件为真(非零),则编译该段代码。 ```c #if CONSTANT_EXPRESSION // 编译此代码块 #endif ``` - **`#ifdef`**:如果某个宏已被定义,则编译接下来的代码块。 ```c #ifdef DEBUG printf("Debug mode is on.\n"); #endif ``` - **`#ifndef`**:如果某个宏未被定义,则编译接下来的代码块。 ```c #ifndef DEBUG printf("Debug mode is off.\n"); #endif ``` - **`#elif`**:用于在`#if`或`#ifdef`之后添加额外的条件分支。 ```c #if CONSTANT_EXPRESSION1 // 编译此代码块 #elif CONSTANT_EXPRESSION2 // 编译此代码块 #endif ``` - **`#else`**:用于在前面所有条件都不满足时编译一段代码。 ```c #if CONSTANT_EXPRESSION // 编译此代码块 #else // 编译此代码块 #endif ``` - **`#pragma`**:用于向编译器发出特殊的指令,具体行为依赖于编译器实现。 ```c #pragma once ``` - **特殊预定义宏**:一些预定义宏提供了关于源文件的信息。 - `__LINE__`:当前源文件的行号。 - `__FILE__`:当前源文件的名称。 - `__DATE__`:文件编译日期。 - `__TIME__`:文件编译时间。 - `__STDC__`:如果编译器遵循ANSI C标准,则定义为1。 ```c #include <stdio.h> int main() { printf("Line: %d\n", __LINE__); // 当前行号 printf("File: %s\n", __FILE__); // 文件名 printf("Date: %s\n", __DATE__); // 编译日期 printf("Time: %s\n", __TIME__); // 编译时间 printf("STDC: %d\n", __STDC__); // 是否符合ANSI C标准 return 0; } ``` 以上是C语言中常用的预处理指令列表及其使用方法[^3]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值