dspmana 发表于 2025-4-26 10:00

C语言基础/逻辑运算/按位运算

在单片机开发中,总有一些C语言基础知识是常常用到的而我们又不易掌握的,今天以STM32单片机为例,总结一下那些常用的C语言基础知识,例如逻辑运算符,结构体,宏定义以及按位运算符。
https://ask.qcloudimg.com/http-save/yehe-7414438/y4vv6cx4gt.png


逻辑运算符
https://ask.qcloudimg.com/http-save/yehe-7414438/p27y8t6d85.png


结构体是32单片机开发中最常用的数据结构了,整个库函数包都是以结构体为基石搭建起来的,因此熟练掌握结构体的使用非常有必要。这里我们就以单片机中最常见到的算法:PID算法来进行示例。声明结构体的一般形式为:            { 成员表列 } ; 例如声明一个包含PID成员变量的结构体:
structPID
{
float P;
float I;
float D;
};             //全局变量
此外还可以在声明结构体时直接定义结构体变量:在结构体定义完后,可以采用两种方式进行初始化:方法一:在声明时直接初始化
structPID
{
      float P;
      float I;
   float D;
} PID_X={1.1,2.0,3.4},PID_Y={2.3,4.2,6.2};   
方法二:在声明后进行额外初始化
https://ask.qcloudimg.com/http-save/yehe-7414438/3y43n1o09a.png


至于结构体变量的引用,就用点(.)运算符就好了:
typedef声明https://ask.qcloudimg.com/http-save/yehe-7414438/p27y8t6d85.png


typedef声明可以定义新的类型名来取代已有的类型名,在STM32单片机开发时常用到的u8 , u16就是这么来的,我们可以双击u8 选中并查看它的定义:
https://ask.qcloudimg.com/http-save/yehe-7414438/vqdidj3x0a.png


1:使用简单的类型名代替复杂的类型名:如上图中的2:定义一个新的类型名来代替结构体类型:#definePI    3.1415926在程序中用3.1415926 原封不动的替换掉 PI 。
原封不动,就是直接替换,不会隐形的添加括号,例如语句:
那么程序中 a*a是什么呢?是 3+3*3+3;而非(3+3)*(3+3)。没有值的宏
没有值的宏常常用来做条件编译宏,比如在程序中我们来检测是否存在该宏,若没有则执行某程序,若有则执行另外的程序。https://ask.qcloudimg.com/http-save/yehe-7414438/y4vv6cx4gt.png


C语言的按位运算符已经非常接近底层操作了,包含六个基本运算符号:
[*]&按位与
[*]|    按位或
[*]~按位取反
[*]^按位异或
[*]<<   左移
[*]>>   右移
上图中红框区域,大家可以这样理解:将00000010 与00000001进行按位或操作,得到的为00000011,在寄存器中因为第七位和第八位(分别控制P6,P7引脚)变为1,则相应引脚被置高。上图红圈一行可以简化a = b | c;,在实际应用中,我们也会见到类似于 a |= b ( a=a | b ) 这样的式子。
按位异或运算便是将两个数的二进制相对应的位比较,相同为0,不同为1,如下图:https://ask.qcloudimg.com/http-save/yehe-7414438/afljxgpf9f.png


13<<3 ;腾出的位置用0填充,超出边界的位被丢弃。
也可以和赋值运算符相结合:
int x = 13 ;
在STM32单片机开发时,左移右移运算符更常用于寄存器开发方式。常用按位运算符技术
1:打开位
下面两项操作打开lottabits中对应于bit表示的位:
2:切换位下面两项操作切换lottabits中 对 应 于bit表 示 的 位 。也就是说,如果位是关闭的,则将被打 开;如果位是打开的,将被关闭 :3 . 关闭位下面的操作将关闭lottabits中对应于bit表示的位 :lottabits = lot t a b i t s & - b i t ;该语句关闭相应的位,而不管它以前的状态如何。首先,运算符〜bit将 原來为1的位设置为0, 原来为0的位设置为1。对0和任意值执行AND操作都将得到0 , 因此关闭相应的位。lottabits中其他所有位都保持不变,这是因为对 1和任意值执行AND操作时,该位的值将保持不变。下面足一种更简洁的方法:lottabits & = - b i t ;

szt1993 发表于 2025-7-31 23:06

C语言基础/逻辑运算/按位运算

jackcat 发表于 2025-8-4 10:11

逻辑运算符(&&, ||, !)的优先级低于算术运算符和关系运算符

albertaabbot 发表于 2025-8-4 12:16

按位运算符优先级低于算术运算符,但高于逻辑运算符。

updownq 发表于 2025-8-4 14:14

在C/C++中,非零值通常被视为真(true),零值被视为假(false)。
这种隐式转换可能导致逻辑错误,特别是当涉及指针或整数时。

saservice 发表于 2025-8-4 18:02

按位运算符的优先级低于加减乘除等基本运算符。因此,在复杂的表达式中使用按位运算时,可能需要使用括号来明确运算顺序。

pixhw 发表于 2025-8-4 19:53

文件内可见,需避免命名冲突。            

mnynt121 发表于 2025-8-5 10:19

明确操作数意图,避免依赖隐式转换的副作用。

mollylawrence 发表于 2025-8-5 12:55

| 维度 | 逻辑运算(&&、||、!) | 按位运算(&、|、^等) |
|----------------|---------------------------------------------------------|---------------------------------------------------------|
| 运算对象 | 操作数为 “真假”(非 0 为真,0 为假) | 操作数为二进制位(对整数的每一位单独运算) |
| 运算结果 | 只有两种:1(真)或0(假) | 结果为整数(按位运算后的二进制值对应的整数) |
| 短路特性 | &&和||具有短路效应(前半部分可确定结果时,不执行后半部分) | 无短路效应,两边操作数都会执行 |
| 典型用途 | 条件判断(if、while的条件表达式) | 位操作(寄存器配置、标志位控制、数据压缩等) |

gygp 发表于 2025-8-7 08:33

位操作的位数应该是非负整数,且在实际应用中通常较小。
整数溢出:左移操作可能导致整数溢出,特别是当移位位数接近或超过操作数的位数时。

ccook11 发表于 2025-8-7 11:33

带符号数的符号位也会被取反,可能导致负数。

adolphcocker 发表于 2025-8-7 13:56

在使用宏定义时,特别是在条件编译指令中,要注意逻辑表达式的正确性和宏展开后的结果。

phoenixwhite 发表于 2025-8-7 16:10

可以使用宏或常量来定义位掩码,提高代码的可读性和可维护性。

uptown 发表于 2025-8-8 10:42

运算符优先级与结合性​            

kkzz 发表于 2025-8-8 12:48

逻辑运算符(&& 和 ||)的优先级低于关系运算符(如 ==, !=, <, > 等)。
使用括号 () 来明确表达式的运算顺序,避免优先级引起的错误。

jtracy3 发表于 2025-8-8 16:08

函数内声明,离开函数后失效。            

qiufengsd 发表于 2025-8-10 21:36

&&:两边操作数均为真(非 0)时,结果为1,否则为0;
&:对两边操作数的每一位做与运算(见后文)。

loutin 发表于 2025-8-11 20:06

按位运算符(&, |, ^, ~, <<, >>)操作的是整数类型的二进制位。

hilahope 发表于 2025-8-11 23:13

全局变量和静态变量默认初始化为 0

mollylawrence 发表于 2025-8-12 02:13

使用按位运算符可以方便地设置、清除或检查特定的位
页: [1] 2
查看完整版本: C语言基础/逻辑运算/按位运算