初出茅庐的小李之C语言必备知识预处理

编译预处理

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

宏定义

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

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

条件编译

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

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

书写格式

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

宏定义的例子

// 定义常量

#include 

#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: %s\n", msg)
#else
    #define DEBUG_PRINT(msg)
#endif




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

这里踩到了一个坑… dev里这个##符号竟然不能使用!看了这个博主的文章才明白
https://blog.csdn.net/leon1741/article/details/78149881,致谢致敬
初出茅庐的小李之C语言必备知识预处理_第1张图片

运行结果

初出茅庐的小李之C语言必备知识预处理_第2张图片

宏定义使用注意事项

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

  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: %d\n", 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("寄存器代码...\r\n");
	#else
	printf("LED库函数代码...\r\n");
	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语言相关,STM32,c语言,开发语言,单片机)