探秘嵌入式位运算:基础与高级技巧
目录
一、位运算基础知识
1.1. 位运算符
1.1.1. 与运算(&)
1.1.2. 或运算(|)
1.1.3. 异或运算(^)
1.1.4. 取反运算(~)
1.1.5. 双重按位取反运算符(~~)
1.1.6. 逻辑取反(!)
1.1.7. 双重逻辑非运算符 (!!)
1.2. 位移运算
1.2.1. 左移运算(<<)
1.2.2. 右移运算(>>)
二、嵌入式位运算基础应用
2.1. 设置标志位
2.2. 清除标志位
2.3. 检查标志位
2.4. 位域
2.5. 硬件控制
2.6. 内存优化
2.7. 加密和校验
三、嵌入式位运算高级技巧
3.1. 位运算优化
3.2. 位运算实现复杂逻辑
3.3. 位运算与硬件接口
3.4. 利用位运算实现快速判断奇偶性
3.5. 不使用临时变量交换两个数
3.6. 求一个数的二进制中1的个数
3.7. 判断一个数是否是2的幂次方
3.8. 利用位运算实现标志位的设置和清除
四、总结
在嵌入式系统开发中,位运算扮演着举足轻重的角色。它允许开发者直接对二进制位进行操作,从而实现数据的高效处理和系统性能的优化。本文深入探讨嵌入式位运算的基础知识与高级技巧,从基本的位操作如与、或、非、异或,到高级的位运算优化、复杂逻辑实现及硬件接口控制等,全面掌握并灵活应用这一关键技能,提升嵌入式系统的性能和稳定性。
一、位运算基础知识
1.1. 位运算符
1.1.1. 与运算(&)
- 规则:当两个对应的二进制位都为1时,结果位才为1,否则为0。
- 示例:5(二进制0101)与3(二进制0011)进行与运算,结果为0001,即1。
- 应用场景:
- 屏蔽某些特定的位。例如,清除一个整数的低两位。
- 检查某个位是否为1(通过与一个只有一个位为1的数进行与运算)。
- 示例代码:
#include <stdio.h>int main() {int a = 5; // 二进制0101int b = 3; // 二进制0011int result = a & b; // 结果为0001,即1printf("a & b = %d\n", result);// 清除低两位int clear_low_two = a & 0b11111100; // 0b表示二进制,结果为0100,即4printf("清除低两位后的a = %d\n", clear_low_two);return 0;
}
运行结果:
1.1.2. 或运算(|)
- 规则:两个对应的二进制位只要有一个为1,结果位就为1。
- 示例:5(二进制0101)或3(二进制0011)进行或运算,结果为0111,即7。
- 应用场景:
- 设置某些特定的位。例如,将一个整数的低两位设置为1。
- 合并两个数的位。
- 示例代码:
#include <stdio.h>int main() {int a = 5; // 二进制0101int b = 3; // 二进制0011int result = a | b; // 结果为0111,即7printf("a | b = %d\n", result);// 设置低两位为1int set_low_two = a | 0b00000011; // 结果为0111,即7printf("设置低两位为1后的a = %d\n", set_low_two);return 0;
}
1.1.3. 异或运算(^)
- 规则:两个对应的二进制位不同时,结果位为1,相同时为0。
- 示例:5(二进制0101)异或3(二进制0011)进行异或运算,结果为0110,即6。
- 应用场景:
- 交换两个变量的值而无需使用临时变量。
- 检查两个数是否相等(如果异或结果为0,则两数相等)。
- 示例代码:
#include <stdio.h>int main() {int a = 5; // 二进制0101int b = 3; // 二进制0011int result = a ^ b; // 结果为0110,即6printf("a ^ b = %d\n", result);// 交换a和b的值a = a ^ b; // a = 0111 (7)b = a ^ b; // b = 0101 (5), a的值已经传递给ba = a ^ b; // a = 0011 (3), b的值已经传递给aprintf("交换后a = %d, b = %d\n", a, b);return 0;
}
1.1.4. 取反运算(~)
- 规则:
- 按位取反运算符
~
作用于一个整数的二进制表示。 - 它将二进制表示中的每一位都进行取反操作,即0变为1,1变为0。
- 结果通常是一个补码表示的整数。
- 按位取反运算符
- 示例:~5(二进制0101)结果为1010,但在有符号整数中,最高位为符号位,因此结果为-6(补码表示)。
- 应用场景:
- 位掩码操作:用于设置、清除或切换特定位。
- 某些加密算法中:作为位操作的一部分。
- 调试和测试:用于检查二进制表示的特定位是否设置。
- 代码示例:
#include <stdio.h>int main() {int a = 5; // 二进制0101int result = ~a; // 结果为1010,但在有符号整数中表示为-6(补码)printf("~a = %d\n", result);// 注意:在有符号整数中,取反后得到的是补码表示的负数// 如果需要得到无符号整数的结果,可以使用无符号类型unsigned int unsigned_a = 5; // 二进制0101unsigned int unsigned_result = ~unsigned_a; // 结果为11111111111111111111111111110101(32位系统),即4294967291(十进制)printf("~unsigned_a (unsigned) = %u\n", unsigned_result);return 0;
}
注意:在C语言中,整数的表示方式(有符号或无符号)会影响取反运算的结果。对于有符号整数,取反后得到的是补码表示的负数;对于无符号整数,取反后得到的是对应位数的全1减去该数的结果。
1.1.5. 双重按位取反运算符(~~)
~~在编程中是一种常用的位运算技巧,主要利用按位取反运算符“~”的特性进行两次取反操作。
- 规则:
- 双重按位取反运算符 “~~” 实际上是对一个值先进行一次按位取反操作(将每一位的 0 变为 1,1 变为 0),然后再进行一次按位取反操作。对于整数类型的值,这通常会将一些特殊的值转换为更 “正常” 的整数值。
- 如果原始值为正整数,第一次取反后变为负数(最高位变为 1),再次取反则变为对应的正整数。如果原始值为负数,第一次取反后变为一个很大的正数(因为负数在计算机中以补码形式存储,取反后得到其绝对值对应的正数减 1 的值),再次取反则变为原来的负数。对于零值,取反两次后仍然是零。
-
示例:
- 假设原始值为 5,其二进制表示为 00000101。
- 第一次取反变为 11111010。
- 再次取反变为 00000101,即又变回了 5。
- 若原始值为 -3,以 8 位二进制表示,原码为 10000011,补码为 11111101。
- 第一次取反变为 00000010。
- 再次取反变为 11111101,即 -3。
- 假设原始值为 5,其二进制表示为 00000101。
- 应用场景:
- 数值转换和规范化:在某些情况下,可能需要将一些特殊的整数值(如从外部输入的可能带有特殊标记的值)转换为正常的整数范围。例如,将可能为 -1 表示无效的值转换为 0 表示有效。可以使用 “~~” 运算符,如果输入值为 -1,取反两次后变为 0。
- 简洁的布尔值转换:在某些情况下,可以将非零值转换为 1,零值转换为 0,类似于布尔值的真和假。虽然可以使用其他方式(如条件表达式)进行这种转换,但 “~~” 运算符可以提供一种简洁的方式。
- 处理特殊标志值:在一些编程场景中,可能使用特定的整数值作为标志,通过双重按位取反可以将这些标志值转换为更易于处理的形式。
- 代码示例:
#include <stdio.h>int main() {int value1 = 5;int result1 = ~~value1;printf("For value1 = %d, double bitwise NOT result is %d\n", value1, result1);int value2 = -3;int result2 = ~~value2;printf("For value2 = %d, double bitwise NOT result is %d\n", value2, result2);int value3 = -1;int result3 = ~~value3;printf("For value3 = %d, double bitwise NOT result is %d\n", value3, result3);return 0;
}
在这个示例中,展示了对不同值使用双重按位取反运算符的结果。程序会输出三个值经过双重按位取反后的结果,验证了上述规则和应用场景。
1.1.6. 逻辑取反(!)
- 规则:
- 逻辑取反运算符
!
作用于一个布尔值或可以转换为布尔值的表达式。 - 它将非零值转换为0(假),将零值转换为1(真)。
- 逻辑取反运算符
- 示例:
!0
的结果是1(真),因为0是假。!5
的结果是0(假),因为5是非零值,被视为真。
- 应用场景:
- 条件判断:在if语句或其他需要布尔值的上下文中使用。
- 逻辑运算:与
&&
(逻辑与)和||
(逻辑或)结合使用,构建复杂的逻辑表达式。
- C语言代码示例:
#include <stdio.h>int main() {int a = 0;int b = 5;int result_a = !a; // 逻辑取反,0变为1(真)int result_b = !b; // 逻辑取反,非0值变为0(假)printf("!%d = %d, !%d = %d\n", a, result_a, b, result_b); // 输出!0 = 1, !5 = 0return 0;
}
1.1.7. 双重逻辑非运算符 (!!)
-
规则:
- 第一个逻辑非 “!” 将操作数转换为布尔值并取反,即非零值变为 false,零值变为 true。
- 第二个逻辑非再次取反,将 false 变为 true,true 变为 false,最终实现将非零值转换为 true,零值转换为 false。
-
示例:如果有一个变量
x
,值为 5。!!x
的结果为 true。如果x
为 0,!!x
的结果为 false。 -
应用场景:
- 在需要明确的布尔值的情况下,可以使用 “!!” 将可能是各种类型的值转换为布尔类型。例如,判断一个指针是否为 NULL,或者判断一个数组是否为空。
- 在一些条件判断中,确保得到一个明确的布尔值可以使代码更加清晰和易于理解。
-
C 语言代码示例:
int x = 5;
bool y =!!x;
if (y) {printf("x is non-zero.\n");
} else {printf("x is zero.\n");
}
在这个例子中,由于 x
非零,所以 y
的值为 true,程序将输出 “x is non-zero.”。
1.2. 位移运算
位移运算分为左移运算和右移运算,它们分别将一个数的二进制表示向左或向右移动指定的位数。
1.2.1. 左移运算(<<)
- 规则:将一个数的二进制位向左移动指定的位数,相当于乘以2的幂次方。左移会丢弃高位(对于有符号数,可能会导致符号位的丢失,从而改变数的符号),低位补0。
- 示例:5(二进制0101)左移2位,结果为20(二进制10100)。
- 应用场景:
- 快速实现乘以2的幂次方的操作。
- 在某些算法中用于位操作和数据打包。
- C语言代码示例:
#include <stdio.h>int main() {int a = 5; // 二进制0101int result = a << 2; // 左移2位,结果为20(二进制10100)printf("%d << 2 = %d\n", a, result);// 验证左移相当于乘以2的幂次方int check_result = a * 4; // 5 * 4 = 20printf("%d * 4 = %d\n", a, check_result);return 0;
}
1.2.2. 右移运算(>>)
- 规则:
- 对于有符号数,右移时会保留符号位(算术右移)。如果最高位(符号位)是1,则左边填充1;如果是0,则左边填充0。
- 对于无符号数,右边用0填充(逻辑右移)。
- 示例:5(二进制0101)右移1位,对于有符号数结果为2(二进制0010);对于无符号数结果也是2(但内部表示可能不同,取决于编译器和平台)。
- 应用场景:
- 快速实现除以2的幂次方的操作(注意,对于负数结果可能不是简单的除法)。
- 在某些算法中用于位操作和数据解包。
- C语言代码示例(有符号数和无符号数的右移):
#include <stdio.h>int main() {int signed_a = 5; // 有符号数,二进制0101int signed_result = signed_a >> 1; // 右移1位,结果为2(二进制0010)printf("%d >> 1 (signed) = %d\n", signed_a, signed_result);unsigned int unsigned_a = 5; // 无符号数,二进制0101unsigned int unsigned_result = unsigned_a >> 1; // 右移1位,结果也为2(但内部表示可能不同)printf("%u >> 1 (unsigned) = %u\n", unsigned_a, unsigned_result);// 验证右移相当于除以2的幂次方int check_result = signed_a / 2; // 5 / 2 = 2printf("%d / 2 = %d\n", signed_a, check_result);// 注意:对于负数,右移的结果可能不是简单的除法int negative_a = -5; // 二进制(补码)11111111111111111111111111111011(32位系统)int negative_result = negative_a >> 1; // 右移1位,结果为-3(算术右移,保留符号位)printf("%d >> 1 (signed, negative) = %d\n", negative_a, negative_result);return 0;
}
注意:
- 对于有符号数的右移,C语言标准规定使用算术右移,即保留符号位。但是,具体的实现可能依赖于编译器和平台。
- 对于无符号数的右移,C语言标准规定使用逻辑右移,即右边用0填充。
- 在处理负数时,右移的结果可能不是简单的除法,因为算术右移会保留符号位并可能导致数值的“向下取整”(向更小的负数方向)。
二、嵌入式位运算基础应用
在嵌入式系统中,位运算是一种高效且常用的操作手段,它允许开发者在不使用复杂数据结构或额外内存的情况下,对硬件寄存器、状态标志等进行精确控制。
2.1. 设置标志位
使用按位或运算(|
)可以将一个数的特定位设置为1,而不影响其他位。这常用于设置硬件寄存器的某个功能位。例如,要设置某个寄存器的第n位为1,可以使用如下操作:寄存器 |= (1 << n)。
#define REGISTER_ADDRESS *((volatile uint32_t*)0x40000000) // 假设寄存器地址
#define BIT_N 3 // 要设置的位void setBitN() {REGISTER_ADDRESS |= (1 << BIT_N); // 设置第BIT_N位为1
}
2.2. 清除标志位
使用按位与运算(&
)和取反运算(~
)可以将一个数的特定位清零,而不影响其他位。这常用于关闭硬件寄存器的某个功能。例如,要清除某个寄存器的第n位,可以使用如下操作:寄存器 &= ~(1 << n)。
void clearBitN() {REGISTER_ADDRESS &= ~(1 << BIT_N); // 清除第BIT_N位
}
2.3. 检查标志位
使用按位与运算,可以检查一个数的特定位是否为1。例如,要检查某个寄存器的第n位是否为1,可以使用如下操作:if (寄存器 & (1 << n))。
int isBitNSet() {return (REGISTER_ADDRESS & (1 << BIT_N)) != 0; // 检查第BIT_N位是否为1
}
2.4. 位域
位域是一种将一个或多个字段打包到一个单一的机器字中的数据结构。位域可以有效地压缩存储空间,并且可以提高程序的执行效率。常用于控制寄存器、状态寄存器等。
struct {unsigned int bit0 : 1;unsigned int bit1 : 1;unsigned int bit2 : 1;unsigned int bit3 : 1;// 其他位域...
} bitField;// 假设bitField位于某个寄存器的地址上,通过指针访问
#define BITFIELD_ADDRESS *((volatile struct { /* 同上结构 */ }*)0x40000004)void setBitFieldBit0() {BITFIELD_ADDRESS.bit0 = 1; // 设置bit0为1
}int isBitFieldBit1Set() {return BITFIELD_ADDRESS.bit1 != 0; // 检查bit1是否为1
}
注意:直接使用位域访问硬件寄存器时,需要确保位域的结构与硬件寄存器的布局完全匹配,并且编译器不会引入额外的内存对齐或填充。
2.5. 硬件控制
通过位运算可以直接操作硬件寄存器的特定位,实现对硬件设备的控制。例如,设置GPIO引脚的输出状态、配置中断控制器等。
// 假设有一个GPIO控制寄存器,其中第0位控制GPIO0的输出状态
#define GPIO_CONTROL_REGISTER *((volatile uint32_t*)0x40020000)void setGPIO0High() {GPIO_CONTROL_REGISTER |= (1 << 0); // 设置GPIO0为高电平
}void setGPIO0Low() {GPIO_CONTROL_REGISTER &= ~(1 << 0); // 设置GPIO0为低电平
}
2.6. 内存优化
位运算可以在不使用额外内存的情况下实现一些复杂的逻辑操作,从而节省内存资源。例如,可以使用位掩码来检查、设置或清除多个标志位。
2.7. 加密和校验
位运算可以用于一些简单的加密算法和数据校验算法中。例如,可以使用循环冗余校验(CRC)算法来检测数据传输中的错误。
注意:在实际应用中,加密和校验算法通常比这里提到的要复杂得多,并且需要使用专门的库或硬件加速器来实现。
位运算在嵌入式系统中具有广泛的应用,从硬件控制到内存优化,再到加密和校验,都离不开位运算的支持。通过熟练掌握位运算的基本操作和应用场景,开发者可以编写出更加高效、可靠的嵌入式系统代码。
三、嵌入式位运算高级技巧
在嵌入式系统开发中,位运算不仅是一种基础技能,更是优化性能、实现复杂逻辑和精确控制硬件设备的关键。
3.1. 位运算优化
在嵌入式系统中,性能优化至关重要。位运算因其高效性而常被用于替代乘法、除法等耗时操作。
示例:使用位运算实现乘法(针对2的幂次方)
#define MULTIPLY_BY_TWO(x) ((x) << 1) // 左移一位相当于乘以2
#define MULTIPLY_BY_FOUR(x) ((x) << 2) // 左移两位相当于乘以4
#define DIVIDE_BY_TWO(x) ((x) >> 1) // 右移一位相当于除以2(注意:结果为整数除法)int main() {int a = 8;int b = MULTIPLY_BY_TWO(a); // b = 16int c = DIVIDE_BY_TWO(a); // c = 4return 0;
}
注意:上述优化仅适用于乘以或除以2的幂次方的情况。对于其他乘法或除法操作,位运算并不能直接替代,但可以通过查表法、分段线性逼近等方法进行近似优化。
3.2. 位运算实现复杂逻辑
位运算不仅可以用于简单的标志位操作,还可以用于实现复杂的逻辑判断和数据处理。例如,可以使用位运算实现状态机的状态转移、数据的压缩和解压缩等。
示例1:使用位运算实现状态机的状态转移
typedef enum {STATE_IDLE,STATE_RUNNING,STATE_ERROR,// 其他状态...
} State;State currentState = STATE_IDLE;void stateMachine(uint8_t event) {switch (currentState) {case STATE_IDLE:if (event & 0x01) { // 假设事件0x01表示启动currentState = STATE_RUNNING;}break;case STATE_RUNNING:if (event & 0x02) { // 假设事件0x02表示错误currentState = STATE_ERROR;} else if (event & 0x03) { // 假设事件0x03表示停止(包含0x01的启动位,但这里通过逻辑判断忽略)currentState = STATE_IDLE;}break;// 其他状态处理...}
}
注意:上述示例中的状态机实现较为简单,实际应用中可能需要更复杂的逻辑判断和状态转移条件。
示例2:数据的压缩和解压缩:可以使用位运算来实现简单的数据压缩算法。例如,将多个小的整数打包到一个较大的整数中,通过位操作来提取和解压这些数据。
// 压缩两个 4 位的整数到一个 8 位的整数
unsigned char compressData(unsigned char data1, unsigned char data2) {return (data1 << 4) | data2;
}// 解压一个 8 位的整数得到两个 4 位的整数
void decompressData(unsigned char compressedData, unsigned char *data1, unsigned char *data2) {*data1 = (compressedData >> 4) & 0x0F;*data2 = compressedData & 0x0F;
}
3.3. 位运算与硬件接口
在嵌入式系统中,许多硬件接口都是通过寄存器进行控制的。通过位运算,可以直接操作这些寄存器,实现对硬件设备的精确控制。例如,可以通过位运算设置GPIO引脚的输出状态、配置定时器的参数等。
示例1:通过位运算设置GPIO引脚的输出状态
#define GPIO_PORT *((volatile uint32_t*)0x40021000) // 假设GPIO端口地址
#define GPIO_PIN 5 // 假设要操作的GPIO引脚编号void setGPIOPin(uint8_t state) {if (state) {GPIO_PORT |= (1 << GPIO_PIN); // 设置GPIO引脚为高电平} else {GPIO_PORT &= ~(1 << GPIO_PIN); // 设置GPIO引脚为低电平}
}
示例2:配置定时器的参数:可以使用位运算来设置定时器的各种参数,如预分频值、计数模式等。
// 假设定时器寄存器地址为 0x40010000
volatile unsigned int *timerRegister = (volatile unsigned int *)0x40010000;// 设置预分频值为 128
*timerRegister &= ~(0xFF << 8);
*timerRegister |= (128 << 8);
3.4. 利用位运算实现快速判断奇偶性
对于一个整数n,如果n & 1
的结果为0,则n是偶数;如果结果为1,则n是奇数。
int isEven(int n) {return !(n & 1); // 如果n & 1为0,则n是偶数,返回1(真);否则返回0(假)
}int isOdd(int n) {return n & 1; // 如果n & 1为1,则n是奇数,返回1(真);否则返回0(假)
}
3.5. 不使用临时变量交换两个数
使用异或运算可以实现不借助临时变量交换两个数的值。
void swap(int *a, int *b) {*a = *a ^ *b;*b = *a ^ *b;*a = *a ^ *b;
}
注意:虽然这种方法很有趣,但在实际应用中,由于现代编译器的优化和处理器指令集的发展,使用临时变量的交换操作通常与这种方法在性能上相差无几,甚至可能更优。因此,在选择交换方法时,应更关注代码的可读性和可维护性。
3.6. 求一个数的二进制中1的个数
可以通过Brian Kernighan算法(也称为“每次消除最低位的1”算法)来高效求解。
int countOnes(int n) {int count = 0;while (n) {n &= (n - 1); // 每次消除最低位的1count++;}return count;
}
注意:这种方法的时间复杂度为O(k),其中k是二进制中1的个数。对于稀疏的二进制数(即1的个数较少),这种方法比逐位检查要快。
3.7. 判断一个数是否是2的幂次方
如果一个数n是2的幂次方,那么n的二进制表示中只有一位是1。可以通过判断n & (n - 1)
是否为0来确定。
int isPowerOfTwo(int n) {return n > 0 && (n & (n - 1)) == 0; // 如果n大于0且n & (n - 1)为0,则n是2的幂次方
}
3.8. 利用位运算实现标志位的设置和清除
在嵌入式系统中,常常需要设置和清除一些标志位。可以使用或运算设置标志位,与运算清除标志位。
// 设置标志位
#define FLAG_BIT 1 << 3
void setFlag(unsigned int *flags) {*flags |= FLAG_BIT;
}// 清除标志位
void clearFlag(unsigned int *flags) {*flags &= ~FLAG_BIT;
}// 检查标志位是否设置
int isFlagSet(unsigned int flags) {return flags & FLAG_BIT;
}
位运算在嵌入式系统开发中具有广泛的应用和重要的价值。通过合理使用位运算技巧,可以优化代码性能、实现复杂逻辑判断和精确控制硬件设备。同时,也需要注意代码的可读性和可维护性,在性能与可读性之间找到平衡点。
四、总结
综上所述,嵌入式位运算是嵌入式开发的核心技能,对系统性能优化至关重要。掌握位运算基础与高级技巧,如位运算优化、复杂逻辑实现、硬件接口控制等,能显著提升代码效率与硬件控制能力。这些技能有助于开发者深入理解嵌入式系统,实现性能与可读性的最佳平衡。
相关文章:
探秘嵌入式位运算:基础与高级技巧
目录 一、位运算基础知识 1.1. 位运算符 1.1.1. 与运算(&) 1.1.2. 或运算(|) 1.1.3. 异或运算(^) 1.1.4. 取反运算(~) 1.1.5. 双重按位取反运算符(~~…...
iOS 17.4 Not Installed
0x00 系统警告 没有安装 17.4 的模拟器,任何操作都无法进行! 点击 OK 去下载,完成之后,依旧是原样! 0x01 解决办法 1、先去官网下载对应的模拟器: https://developer.apple.com/download/all/?q17.4 …...
RestTemplate 使用教程
RestTemplate 是 Spring 框架提供的一种用于执行HTTP请求的同步客户端。它简化了与HTTP服务器的交互,并支持RESTful Web服务。 1. 添加依赖 首先,确保你的项目中包含了Spring Web的支持。如果你使用的是Maven,在pom.xml文件中添加如下依赖&…...
windows下安装wsl的ubuntu,同时配置深度学习环境
写在前面,本次文章只是个人学习记录,不具备教程的作用。个别信息是网上的,我会标注,个人是gpt生成的 安装wsl 直接看这个就行;可以不用备份软件源。 https://blog.csdn.net/weixin_44301630/article/details/1223900…...
【贪心算法第五弹——300.最长递增子序列】
目录 1.题目解析 题目来源 测试用例 2.算法原理 3.实战代码 代码解析 注意本题还有一种动态规划的解决方法,贪心的方法就是从动态规划的方法总结而来,各位可以移步博主的另一篇博客先了解一下:动态规划-子序列问题——300.长递增子序列…...
【数据分析】基于GEE解析2000-2020年武汉市FVC时空变化特征
武汉市FVC时空变化特征解析 1. 写在前面2. 2000~2020年武汉市FVC时空变化特征解析2.1. 数据获取与预处理2.2. 辐射定标和大气校正2.3. 云层和云影去除2.4. FVC计算2.5. 时空分析2.6. 代码1. 写在前面 🌍✨在应对全球气候变化和环境监测的挑战中,植被盖度(Fraction Vegetati…...
springboot实战(19)(条件分页查询、PageHelper、MYBATIS动态SQL、mapper映射配置文件、自定义类封装分页查询数据集)
引言: 该类博客的学习是基于b站黑马视频springbootvue视频学习!具体围绕项目——"大事件"进行实战学习。 目录 一、功能介绍(需求)。 1、文章列表功能基本介绍。 2、条件分页查询功能与注意。 3、前端页面效果。&#x…...
Mongo数据库 --- Mongo Pipeline
Mongo数据库 --- Mongo Pipeline 什么是Mongo PipelineMongo Pipeline常用的几个StageExplanation with example:MongoDB $matchMongoDB $projectMongoDB $groupMongoDB $unwindMongoDB $countMongoDB $addFields Some Query Examples在C#中使用Aggreagtion Pipeline**方法一: …...
Docker部署mysql:8.0.31+dbsyncer
Docker部署mysql8.0.31 创建本地mysql配置文件 mkdir -p /opt/mysql/log mkdir -p /opt/mysql/data mkdir -p /opt/mysql/conf cd /opt/mysql/conf touch my.config [mysql] #设置mysql客户端默认字符集 default-character-setUTF8MB4 [mysqld] #设置3306端口 port33…...
银河麒麟桌面系统——桌面鼠标变成x,窗口无关闭按钮的解决办法
银河麒麟桌面系统——桌面鼠标变成x,窗口无关闭按钮的解决办法 1、支持环境2、详细操作说明步骤1:用root账户登录电脑步骤2:导航到kylin-wm-chooser目录步骤3:编辑default.conf文件步骤4:重启电脑 3、结语 Ὁ…...
【微服务】 Eureka和Ribbon
一、Eureka 服务调用出现的问题:在远程调用另一个服务时,我们采用的解决办法是发送一次http请求,每次环境的变更会产生新的地址,所以采用硬编码会出现很多麻烦,并且为了应对并发问题,采用分布式部署&#…...
C++设计模式(工厂模式)
一、介绍 1.动机 在软件系统中,经常面临着创建对象的工作,这些对象有可能是一系列相互依赖的对象;由于需求的变化,需要创建的对象的具体类型经常变化,同时也可能会有更多系列的对象需要被创建。 如何应对这种变化&a…...
nodejs第三方库sharp对图片的操作生成新图片、压缩、添加文字水印及图片水印等
Sharp是一个基于libvips的高性能Node.js图像处理库,它提供了广泛的功能,包括调整大小、裁剪、旋转、格式转换等。Sharp可以处理多种图像格式,并且能够高效地转换图像格式。 相关说明及用法看:https://sharp.nodejs.cn/ 安装&#…...
uniapp-vue2引用了vue-inset-loader插件编译小程序报错
报错信息 Error: Vue packages version mismatch: - vue3.2.45 (D:\qjy-myApp\admin-app\node_modules\vue\index.js) - vue-template-compiler2.7.16 (D:\qjy-myApp\admin-app\node_modules\vue-template-compiler\package.json) This may cause things to work incorrectly.…...
计算机的错误计算(一百六十七)
摘要 将计算机的错误计算(一百六十六)中算式的分母有理化,然后再在 MATLAB 讨论其计算精度。本节说明,MATLAB 的输出与(一百六十六)的输出几乎一致,有效数字的错误率也相同。 例1. 探讨 …...
交叉编译openSSH
升级原系统中的SSHd服务 由于原系统自带的SSH版本过低存在漏洞风险,所以需要升级新版本的SSH 交叉编译前准备 需要下面三个库,都是开源的,去对应的网站下载即可 openssh-9.6p1.tar.gz openssl-1.1.1w.tar.gz zlib-1.3.1.tar.gz 这里没有…...
从零开始学GeoServer源码(二)添加支持arcgis切片功能
文章目录 参考文章环境背景1、配置打包好的程序1.1、下载GeoServer的war包1.2、下载GeoWebCache1.3、拷贝jar包1.4、修改配置文件1.4.1、拷贝geowebcache-arcgiscache-context.xml1.4.2、修改geowebcache-core-context.xml1.4.3、修改geowebcache-servlet.xml 1.5、配置切片信息…...
Android OTA 更新面试题及参考答案
什么是 OTA 更新? OTA 更新即空中下载技术(Over-the-Air Technology)更新,是一种通过无线网络对移动设备的系统软件或应用程序进行远程更新的技术手段 。 其原理是设备通过移动网络或 Wi-Fi 连接到服务器,服务器检测设…...
搜维尔科技:通过Touch力反馈主手实时通讯机械臂,进行远程操作
通过Touch力反馈主手实时通讯机械臂,进行远程操作 搜维尔科技:通过Touch力反馈主手实时通讯机械臂,进行远程操作...
Java ArrayList 与顺序表:在编程海洋中把握数据结构的关键之锚
我的个人主页 我的专栏:Java-数据结构,希望能帮助到大家!!!点赞❤ 收藏❤ 前言:在 Java编程的广袤世界里,数据结构犹如精巧的建筑蓝图,决定着程序在数据处理与存储时的效率、灵活性以…...
React中事件处理和合成事件:理解与使用
🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课签约作者、上架课程《Vue.js 和 E…...
在Vue3项目中引入省市区联动插件
1. 打开HBuilder X 图1 2. 新建一个空项目 文件->新建->项目->uni-app 填写项目名称:vue3demo 选择项目存放目录:D:/HBuilderProjects 一定要注意vue的版本,当前选择的版本为vue3 图2 点击“创建”之后进入项目界面 图3 其中各文件…...
动态内存管理(c语言)
我们通常开辟空间的方式 int val 20; //大小为4个字节 char arr[10] {0} //开辟出一块连续的空间且大小为10 但是上面开辟空间方式的特点 1.空间开辟大小是固定的 2.数组在声明得时候,必须指定数组得长度,它所需要得内存在编译时分配 但是以上的方式不能…...
SLF4J日志快速上手
tags: SpringBoot 日志 快速上手 SLF4J日志快速上手 第一步:添加日志相关配置 logging:level:root: INFO # 设置全局日志级别为 INFO,只显示重要的日志信息(略过 DEBUG 和 TRACE 级别)# org.hibernate.SQL: DEBUG # 对于 Hiber…...
【PyTorch】(基础三)---- 图像读取和展示
图像读取和展示 pytorch本身并不提供图像的读取和展示功能,利用pytorch执行计算机视觉任务的时候,通常是利用opencv等工具先进行图像处理,然后将结果转化成tensor类型传递给pytorch,在pytorch执行之后,也可以将tensor…...
【纪念365天】我的创作纪念日
过去的一年 没有注意加入csdn已经有一年了。 这几天翻看小猴儿的通知才发现时间来到了一年的纪念日。稍稍思索想要将这一段时间的学习到的知识以及偶然遇到的机遇做一下总结。 上一次写纪念日是来到csdn128天的时候, 200天前我的学习状态是非常疯狂的。 只记得我当时…...
flink学习(7)——window
概述 窗口的长度(大小): 决定了要计算最近多长时间的数据 窗口的间隔: 决定了每隔多久计算一次 举例:每隔10min,计算最近24h的热搜词,24小时是长度,每隔10分钟是间隔。 窗口的分类 1、根据window前是否调用keyBy分为键控窗口和非键控窗口…...
第十六届蓝桥杯模拟赛第二期题解—Java
第十六届蓝桥杯模拟赛/校赛第二期个人题解,有错误的地方欢迎各位大佬指正 问题一(填空题) 【问题描述】 如果一个数 p 是个质数,同时又是整数 a 的约数,则 p 称为 a 的一个质因数。 请问, 2024 的最大的质因数是多少? …...
数据库-MySQL-Dynamic-Datasource源码解析
文章目录 前言一、简介二、整体流程三、核心解析四、总结 前言 多数据源的应用在日常项目中也是很常见的场景。 dynamic-datasource的功能,用起来的确很方便,只需要一个DS注解,加上一些简单的配置即可完成多数据源的切换。究竟是怎么做到的…...
uniapp+vue2+uview2.0导航栏组件二次封装
样式 代码 <template><view class"navBar"><u-navbar :title"title" :titleColor"titleColor" :bgColor"bgColor" :safeAreaInsetTop"safeAreaInsetTop":autoBack"true" leftClick"leftClic…...
【Git 工具】用 IntelliJ IDEA 玩转 Git 分支与版本管理
文章目录 一、使用 IDEA 配置和操作 Git1.1 查看 Idea 中的 Git 配置1.2 克隆 Github 项目到本地 二、版本管理2.1 提交并推送修改2.2 拉取远程仓库2.3 查看历史2.4 版本回退 三、分支管理3.1 新建分支3.2 切换分支3.2 合并分支3.4 Cherry-Pick 参考资料 一、使用 IDEA 配置和操…...
异或-java-leetcode
1486.数组异或操作 给你两个整数,n 和 start 。 数组 nums 定义为:nums[i] start 2*i(下标从 0 开始)且 n nums.length 。 请返回 nums 中所有元素按位异或(XOR)后得到的结果。 示例 1: 输入…...
Jmeter中的测试片段和非测试原件
1)测试片段 1--测试片段 功能特点 重用性:将常用的测试元素组合成一个测试片段,便于在多个线程组中重用。模块化:提高测试计划的模块化程度,使测试计划更易于管理和维护。灵活性:可以通过模块控制器灵活地…...
NeurIPS 2024 有效投稿达 15,671 篇,数据集版块内容丰富
NeurIPS,全称 Neural Information Processing Systems Conference,是神经信息处理系统的年度学术会议。该会议始于 1987 年,当时名为 NIPS。随着人工智能领域的快速发展,其影响力逐渐扩大,被越来越多的研究者和企业关注…...
力扣101. 对称二叉树
给你一个二叉树的根节点 root , 检查它是否轴对称。 提示: 树中节点数目在范围 [1, 1000] 内-100 < Node.val < 100 进阶:你可以运用递归和迭代两种方法解决这个问题吗? 代码: /*** Definition for a binary …...
Ubuntu 环境下的 C/C++ 编译与调试配置
详细教学文档:Ubuntu 环境下的 C/C 编译与调试配置 本文档将手把手引导你完成在 Ubuntu 环境中设置 VS Code 的 tasks.json 和 launch.json,实现以下目标: 统一管理输出文件:将所有编译生成的可执行文件统一存放到项目的 build …...
『VUE』36. Vue的应用概念(分析流程)
目录 创建应用挂载应用可执行文件公共资源总结 欢迎关注 『VUE』 专栏,持续更新中 欢迎关注 『VUE』 专栏,持续更新中 创建应用 首先引入createApp ,然后借助createApp 创造一个app对象 main.js import { createApp } from "vue"; import A…...
《基于FPGA的便携式PWM方波信号发生器》论文分析(三)——数码管稳定显示与系统调试
一、论文概述 基于FPGA的便携式PWM方波信号发生器是一篇由任青颖、庹忠曜、黄洵桢、李智禺和张贤宇 等人发表的一篇期刊论文。该论文主要研究了一种新型的信号发生器,旨在解决传统PWM信号发生器在移动设备信号调控中存在的精准度低和便携性差的问题 。其基于现场可编…...
mac上的建议xftp 工具
mac上的建议xftp 工具 最近使用mac比较频繁了,但是第一次重度使用mac里面有很多的工具都是新的,有的window版本的工具无法使用。 xftp 的平替 Cyberduck 从它的官网上下载是免费的,但是如果使用 Apple store 要花费198呢。这不就剩下一大笔…...
Hive | Hive 表如何查看所有分区
文章目录 概述使用 SHOW PARTITIONS 命令查看特定分区的信息获取详细的分区信息总结 概述 Apache Hive 是一个构建在 Hadoop 之上的数据仓库工具,它提供了 SQL 类似的查询语言(称为 HiveQL),使得用户能够更容易地进行大数据处理和…...
MySQL系列之数据类型(Numeric)
导览 前言一、数值类型综述二、数值类型详解1. NUMERIC1.1 UNSIGNED或SIGNED1.2 数据类型划分 2. Integer类型取值和存储要求3. Fixed-Point类型取值和存储要求4. Floating-Point类型取值和存储要求 结语精彩回放 前言 MySQL系列最近三篇均关注了和我们日常工作或学习密切相关…...
4.6 JMeter HTTP信息头管理器
欢迎大家订阅【软件测试】 专栏,开启你的软件测试学习之旅! 文章目录 前言1 HTTP信息头管理器的位置2 常见的HTTP请求头3 添加 HTTP 信息头管理器4 应用场景 前言 在 JMeter 中,HTTP信息头管理器(HTTP Header Manager)…...
fpga 综合与优化设计
目录 Quartus Prime优化设置 1. 分析与综合设置 2. 物理综合优化 3. 适配设置 描述方法对综合的影响 1. 操作符的应用差异 2. 条件语句和分支语句的应用差异 3. 描述方式对综合电路的影响 优化设计方法 1. FPGA设计的基本原则 2. 常用优化设计方法 优化主要包括 4 个…...
计算机毕业设计Hadoop+Spark音乐推荐系统 音乐预测系统 音乐可视化大屏 音乐爬虫 HDFS hive数据仓库 机器学习 深度学习 大数据毕业设计
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...
C嘎嘎探索篇:栈与队列的交响:C++中的结构艺术
C嘎嘎探索篇:栈与队列的交响:C中的结构艺术 前言: 小编在之前刚完成了C中栈和队列(stack和queue)的讲解,忘记的小伙伴可以去我上一篇文章看一眼的,今天小编将会带领大家吹奏栈和队列的交响&am…...
摄像头原始数据读取——opencv(cv::VideoCapture)
摄像头原始数据读取——opencv(cv::VideoCapture) 测试代码test.cpp #include <iostream> #include <string>#include <opencv2/opencv.hpp>std::string pixeformatcodec2string(int codec) {char pixeformat_name[5] { (char)((codec >> 0) & …...
unreal engine5中多个摄像机切换
UE5系列文章目录 文章目录 UE5系列文章目录前言一、思路二、具体实现 前言 unreal engine5中使用蓝图实现多个相机切换 一、思路 在Unreal Engine 5中,如果你想要在控件蓝图(Widget Blueprint)中获取场景摄像机的信息,可以按照…...
ensp静态路由实验
一、实验目的 1、熟练掌握交换机的基本配置命令 2、熟练掌握静态路由的使用方法 3. 熟练掌握交换机端口模式 二、实验内容 需求: 根据要求利用现有实验设备组建小型局域网 实验设备: 交换机S37002台;PC机2台;路由器2台。 …...
【在Linux世界中追寻伟大的One Piece】多线程(二)
目录 1 -> 分离线程 2 -> Linux线程互斥 2.1 -> 进程线程间的互斥相关背景概念 2.2 -> 互斥量mutex 2.3 -> 互斥量的接口 2.4 -> 互斥量实现原理探究 3 -> 可重入VS线程安全 3.1 -> 概念 3.2 -> 常见的线程不安全的情况 3.3 -> 常见的…...
Git中HEAD、工作树和索引的区别
在Git版本控制系统中,HEAD、工作树(Working Tree)和索引(Index)是三个非常重要的概念,它们分别代表了不同的状态或区域,下面我将对这三个概念进行详细的解释。 HEAD 定义:HEAD是一…...