一、给寄存器的某个位进行赋值
C语言基础知识(位操作)
运算符 | 含义 | 运算符 | 含义 |
& | 按位与 | ~ | 按位取反 |
| | 按位或 | << | 左移 |
^ | 按位异或 | >> | 右移 |
我们定义一个32位的寄存器变量:unit32_t temp=0;
从左到右依次是第1位,第2位......第32位
我们现在给第5位赋值,也就是让第5位为1,从右往左依次是1,2,3......32位。
我们主要有以下四种方法:
第一种方法是按位与:也就是让第5位为0,其余为1,即temp = temp&0xFFFFFF7F
第二种方法是按位或:也就是让第五位为1,其余为0,即temp = temp|0x00000010
第三种方法是左移操作与:让第五位为1,也就是让1左移5位,再取反temp&=~(1<<5)
第四种方法是左移操作或:让第五位为1,也就是让1左移5位,temp|=1<<5。
按位异或用于控制位5翻转:temp^=1<<5;0和任何数异或都是任何数
二、宏定义
宏定义的优点:
1. 增强代码的可读性和可维护性:使用宏定义可以将代码中某些常用的数值或字符串定义为常量,使代码更具可读性和可维护性。
2. 提高代码的复用性:使用宏定义可以避免代码重复编写,提高代码的复用性。
3. 方便代码的修改:使用宏定义可以方便地修改代码中的某些常量值,避免了修改多处代码的麻烦。
4. 优化代码的执行效率:使用宏定义可以将一些常量或表达式在编译期间计算,避免了运行时的计算,从而提高了代码的执行效率。
5. 增强代码的可移植性:通过定义宏,可以将代码中某些与平台相关的常量和特殊处理方法独立出来,增强了代码的可移植性。
无参宏定义:
# define 标识符 字符串
标识符:宏定义的名字
字符串:常数、表达式、格式串等。
eg:
# define PI 3.14159
# define HSE_VALUE 8000000000
用前边来替换后边
有参宏定义:
# define LED1(x) do {x?\
HAL_GPIO_WritePin(LED1_GPIO_P0RT,LED1_GPIO_PIN,GPIO_PIN_SET):\
HAL_GPIO_WritePin(LED1_GPIO_P0RT,LED1_GPIO_PIN,GPIO_PIN_RESET):\
}while(0)
其中用到C语言中的条件运算符,x?A:B,表示如果X为真,则结果为A,否则结果为B。
建议使用do{...}while(0)来构造宏定义
这样不会受到大括号、分号、运算符优先级等的影响,总是按照你的期望进行
我们看一下谷歌大佬 Robert Love ,对do{} while(0)的说法
do {…} while(0) is the only construct in C that lets you define macros that
always work the same way, so that a semicolon after your macro always has the
same effect, regardless of how the macro is used (with particularly emphasis
on the issue of nesting the macro in an if without curly-brackets).
翻译:
使用do {...} while(0)
构造后的宏定义不会受到大括号、分号等影响,总能按照我们期望的方式调用运行。
例如:
我们定义一个宏定义,宏名是fool(x),后边 bar(x),baz(x)是我们字符串的内容了,我们看到有两个函数,第一个函数有分号,第二个没有。这样不会报错,因为宏定义不会对语法内容进行检测的。
#define fool(x) bar(x); baz(x)
然后你这样调用
fool(wolf);
这样的话,宏将会被扩展为
bar(wolf);baz(wolf);
接下来我们再看一个例子,就可以看到do{} while(0)写法的规范
我们期望的正确结果是这样的
if (!feral)
fool(wolf)
但是扩展以后就是这样的,不是我们所期待的样子
if (!feral)
bar(wolf);
baz(wolf);
显而易见,这是错误的,这是大家最容易犯错的
三、条件编译
条件编译是根据预定义的条件决定编译哪些代码的一种方式。常见的条件编译有以下几种:
1. #ifdef和#ifndef:判断是否定义了某个宏定义,语法格式为:#ifdef宏定义 或者 #ifndef宏定义。
2. #if、#elif和#else:这种方式可以根据表达式结果选择编译哪些代码,语法格式为:#if 表达式1 、#elif 表达式2 或 #else。
3. #define和#undef:这种方式可以定义或取消宏定义,语法格式为:#define宏定义 或 #undef宏定义。
4. #include:这种方式可以在编译期间将指定文件的内容包含到当前文件中,语法格式为:#include文件名。
实际上,条件编译是将一些不需要或不能运行的代码在预处理中被过滤掉,从而让代码编译时只编译需要的代码。这样可以大大提高程序的效率和安全性。
举个例子”头文件的条件编译“
#ifndef _LED_H
#define _LED_H
#include "./SYSTEM/sys/sys.h"
code
#endif
四、extern 声明
extern 声明用于声明一个变量或函数是在别处定义的,而不是在当前文件中定义的。放在函数/变量前,表示此函数/变量在其他文件定义,以便本文件引用
extern uint16_t g_usart_rx_sta;
extern void delay_us(uint32_t nus)