0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

C语言必备知识编译预处理

CHANBAEK 来源:小李的创客实验室 作者: 初出茅庐的小李 2023-12-01 18:27 次阅读

C语言必备知识编译预处理

编译预处理就是在编译源代码之前进行的一系列处理,将源程序中的一些特殊命令进行展开或处理,生成扩展的源代码。这些特殊命令通常以“#”开头,占单独的行,语句尾部不需要加分号。

宏定义

(#define)是一种常见的编译预处理指令,用于定义宏,实现代码的简化和重用。

文件包含(#include)用于在源文件中引入其他文件的内容,方便代码模块化和复用。

条件编译

(#if, #else, #endif等)允许根据条件选择性地编译部分代码,提高代码的灵活性。

在预处理阶段,这些指令会被解释和处理,生成经过预处理的源代码,然后再经过编译、汇编、链接等步骤生成最终的可执行文件。这个过程有助于提高代码的可维护性和可移植性。

书写格式

以“#”开头、占单独行、语句尾不加分号。这样的规范有助于编译器正确解释和处理这些指令,同时也使得代码更加清晰易读。这样的一致性规范有助于维护代码时的可读性和可理解性。

宏定义的例子

// 定义常量

#include < stdio.h >

#define MAX_SIZE 100
#define PI 3.1415926

// 简化代码
#define SQUARE(x) ((x) * (x))
#define MAX(a, b) ((a) > (b) ? (a) : (b))


#define DEBUG   //只要定义了该宏 DEBUG_PRINT就会起作用 没有定义则不起作用 

// 字符串拼接

//#define CONCAT_STR(a,b) a##b dev平台用不了 linux未测试
#define CONCAT_STR(a,b) a b

// 条件编译
#ifdef DEBUG
    #define DEBUG_PRINT(msg) printf("Debug: %sn", msg)
#else
    #define DEBUG_PRINT(msg)
#endif




int main(void) 
{
	
	printf("5的平方是%drn",SQUARE(5));
	printf("MAX(2,3)返回较大的一个数是%drn",MAX(2,3)) ;
	DEBUG_PRINT("调试信息"); 
	printf("%srn", CONCAT_STR("你好", "World"));  // 这里会被展开为 printf("%srn", "你好, " "World");
}

这里踩到了一个坑............. dev里这个##符号竟然不能使用!看了这个博主的文章才明白 https://blog.csdn.net/leon1741/article/details/78149881,致谢致敬图片

运行结果

图片
在这里插入图片描述

宏定义使用注意事项

使用宏定义时需要注意一些事项,以确保代码的可读性和正确性。以下是一些宏定义的注意事项:

  1. 括号的使用:
    在宏定义中,为了避免优先级问题,通常在宏的参数和整体表达式外部都使用括号。例如:

    #define SQUARE(x) ((x) * (x))
    

    这样可以确保在使用时不会出现预期之外的行为。

  2. 避免副作用:
    在宏中避免使用具有副作用的表达式,因为宏是简单的文本替换,可能导致意外的行为。

    // 避免这样的宏定义
    #define INCREMENT(x) x++
    
  3. 使用大写字母:
    为了与变量和函数名区分,宏的名称通常使用大写字母。

    #define MAX_SIZE 100
    
  4. 多行宏的注意:
    如果宏跨越多行,确保在每行的末尾使用反斜杠 连接,以避免语法错误。

    #define PRINT_SUM(a, b) 
        do { 
            int sum = (a) + (b); 
            printf("Sum: %dn", sum); 
        } while(0)
    
  5. 参数的使用:
    宏参数的使用要小心,确保在宏展开时不会导致预期之外的结果。

    // 不要这样使用,可能导致问题
    #define SQUARE(x) x * x
    
  6. 条件编译:
    在使用条件编译时,确保相关的宏定义和取消定义都是正确的。

    #ifdef DEBUG
        // ...
    #endif
    

总体来说,清晰、简洁、避免副作用是设计宏定义时的关键原则。良好的宏定义可以提高代码的可读性和可维护性。

单片机中可以使用预编译来区分代码版本

如果定义了REG_CODE 这个宏且其结果是1那么就是寄存器版本代码否则就是库函数版本代码

void LED_Config(void)
{
	#if (REG_CODE)
	
	RCC- >AHB1ENR |= 1< < 2;      //GPIOC的时钟开关

	GPIOC- >MODER &= ~(3< < 2*4);//把89位清00 PC4
	GPIOC- >MODER |=  (1< < 2*4);//只是把第89位置01
	
	GPIOC- >MODER &= ~(3< < 2*5);//把10 11位清00 PC5
	GPIOC- >MODER |=  (1< < 2*5);//只是把第89位置01
	
	GPIOC- >MODER &= ~(3< < 2*6);//把11 12位清00 PC6
	GPIOC- >MODER |=  (1< < 2*6);//只是把第89位置01
	
	GPIOC- >MODER &= ~(3< < 2*7);//把89位清00  PC7
	GPIOC- >MODER |=  (1< < 2*7);//只是把第89位置01
	
	GPIOC- >OTYPER &= ~(1< < 4); //推挽模式//0xFFFF FFEF 
	GPIOC- >OTYPER &= ~(1< < 5);
	GPIOC- >OTYPER &= ~(1< < 6);
	GPIOC- >OTYPER &= ~(1< < 7);
	
	
	//假设输出状态 灯的开关
	GPIOC- >ODR |=  (1< < 4)| (1< < 5)|(1< < 6) |(1< < 7);  //默认全关
	printf("寄存器代码...rn");
	#else
	printf("LED库函数代码...rn");
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
	
    GPIO_InitTypeDef  GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Mode   = GPIO_Mode_OUT;
	GPIO_InitStruct.GPIO_OType  = GPIO_OType_PP;
	GPIO_InitStruct.GPIO_Pin    = GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
	GPIO_InitStruct.GPIO_PuPd   = GPIO_PuPd_NOPULL;
	GPIO_InitStruct.GPIO_Speed  = GPIO_High_Speed;
	
	GPIO_Init(GPIOB,&GPIO_InitStruct);
	
	
	#endif
	
}

至此,预编译相关的知识点就介绍完了。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • C语言
    +关注

    关注

    180

    文章

    7604

    浏览量

    136680
  • 源代码
    +关注

    关注

    96

    文章

    2945

    浏览量

    66730
  • 代码
    +关注

    关注

    30

    文章

    4779

    浏览量

    68519
  • 编译
    +关注

    关注

    0

    文章

    657

    浏览量

    32851
  • 预处理
    +关注

    关注

    0

    文章

    33

    浏览量

    10478
收藏 人收藏

    评论

    相关推荐

    C语言常用的预处理命令

    1.基础知识(1)C语言常用的预处理命令——typedef具体可见C语言基础语法
    发表于 07-14 07:10

    c语言预处理命令以什么开头

    c语言预处理命令以什么开头,目前我并没有windows软件编写经验,对C语言的应用也仅限于各种单片机的编程,所以对
    发表于 07-20 07:00

    介绍一下C语言预处理知识与宏定义原理

    系统平台上的gcc)前言本篇文章将会向大家介绍一下C语言预处理知识、宏定义、函数、以及编译执行程序所需的静态链接库和动态链接库的一些原理,
    发表于 02-11 06:35

    C语言编译预处理

    在将一个C源程序转换为可执行程序的过程中, 编译预处理是最初的步骤. 这一步骤是由预处理器(preprocessor)来完成的. 在源流程序被编译
    发表于 09-20 18:17 47次下载

    基于51单片机--C语言预处理总结

    编译预处理器是C语言编译器的一个重要组成部分。很好的利用C
    发表于 08-17 10:48 1080次阅读

    C程序设计教程之如何进行编译预处理

    预处理C 语言的一个重要功能,它由预处理程序负责完成。所谓预处理是指在进行编译的第一遍扫描(
    发表于 11-02 15:47 5次下载

    C语言程序设计教程之如何进行函数与编译预处理资料概述

    本文档的主要内容详细介绍的是C语言程序设计教程之如何进行函数与编译预处理资料概述主要内容包括了:1 函数概述2 函数定义与调用3 局部变量和全局变量4 变量的生存期和存储类别5
    发表于 12-10 17:16 4次下载
    <b class='flag-5'>C</b><b class='flag-5'>语言</b>程序设计教程之如何进行函数与<b class='flag-5'>编译</b><b class='flag-5'>预处理</b>资料概述

    C语言程序设计教程之编译预处理的详细资料说明

    本文档的主要内容详细介绍的是C语言程序设计教程之编译预处理的详细资料说明主要内容包括了:1.宏定义 2.文件包含 3.条件编译
    发表于 01-08 14:19 2次下载
    <b class='flag-5'>C</b><b class='flag-5'>语言</b>程序设计教程之<b class='flag-5'>编译</b><b class='flag-5'>预处理</b>的详细资料说明

    浅析VerilogHDL编译系统的预处理

    。在Verilog HDL语言编译时,特定的编译指令在整个编译过程中有效(编译过程可跨越多个文件),直到遇到其他不同的
    发表于 03-26 16:10 762次阅读

    C语言预处理命令的分类和工作原理详细说明

    器,故在阅读或开发 C/C++ 程序过程中,可能会接触大量的预处理指令。 1、预处理指令及分类 C/C
    发表于 11-25 10:34 18次下载
    <b class='flag-5'>C</b><b class='flag-5'>语言</b><b class='flag-5'>预处理</b>命令的分类和工作原理详细说明

    C语言预处理指令及分类

    C/C++ 程序中的源代码中包含以 # 开头的各种编译指令,这些指令称为预处理指令。预处理指令不属于 C
    的头像 发表于 11-29 10:14 2255次阅读

    C语言宏定义与预处理、函数和函数库

    系统平台上的gcc)前言本篇文章将会向大家介绍一下C语言预处理知识、宏定义、函数、以及编译执行程序所需的静态链接库和动态链接库的一些原理,
    发表于 12-07 21:06 2次下载
    <b class='flag-5'>C</b><b class='flag-5'>语言</b>宏定义与<b class='flag-5'>预处理</b>、函数和函数库

    C语言-预处理(#define、#if...)

    C语言程序里,出现的#开头的代码段都属于预处理预处理:是在程序编译阶段就执行的代码段。
    的头像 发表于 08-14 10:13 2449次阅读

    为什么C语言要进行编译

    为什么我们编写的C语言要进行编译?什么是编译编译时发生了什么? 机器无法理解我们编写的C
    的头像 发表于 11-24 15:47 1319次阅读
    为什么<b class='flag-5'>C</b><b class='flag-5'>语言</b>要进行<b class='flag-5'>编译</b>

    C语言有哪些预处理操作?

    C语言预处理是在编译之前对源代码进行处理的阶段,它主要由预处理器完成。
    的头像 发表于 12-08 15:40 611次阅读
    <b class='flag-5'>C</b><b class='flag-5'>语言</b>有哪些<b class='flag-5'>预处理</b>操作?