探秘嵌入式位运算:基础与高级技巧

目录

一、位运算基础知识

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。
  • 应用场景:
    • 数值转换和规范化:在某些情况下,可能需要将一些特殊的整数值(如从外部输入的可能带有特殊标记的值)转换为正常的整数范围。例如,将可能为 -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;
}

位运算在嵌入式系统开发中具有广泛的应用和重要的价值。通过合理使用位运算技巧,可以优化代码性能、实现复杂逻辑判断和精确控制硬件设备。同时,也需要注意代码的可读性和可维护性,在性能与可读性之间找到平衡点。 

四、总结

综上所述,嵌入式位运算是嵌入式开发的核心技能,对系统性能优化至关重要。掌握位运算基础与高级技巧,如位运算优化、复杂逻辑实现、硬件接口控制等,能显著提升代码效率与硬件控制能力。这些技能有助于开发者深入理解嵌入式系统,实现性能与可读性的最佳平衡。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/60883.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL底层概述—3.InnoDB线程模型

大纲 1.InnoDB的线程模型 2.IO Thread 3.Purge Thread 4.Page Cleaner Thread 5.Master Thread 1.InnoDB的线程模型 InnoDB存储引擎是多线程的模型&#xff0c;因此其后台有多个不同的后台线程&#xff0c;负责处理不同的任务。 后台线程的作用一&#xff1a;负责刷新内存…

pikachu平台xss漏洞详解

声明&#xff1a;文章只是起演示作用&#xff0c;所有涉及的网站和内容&#xff0c;仅供大家学习交流&#xff0c;如有任何违法行为&#xff0c;均和本人无关&#xff0c;切勿触碰法律底线 文章目录 概述&#xff1a;什么是xss一、反射型XSS1. get2. post 二、存储型XSS三、DOM…

Easyexcel(7-自定义样式)

相关文章链接 Easyexcel&#xff08;1-注解使用&#xff09;Easyexcel&#xff08;2-文件读取&#xff09;Easyexcel&#xff08;3-文件导出&#xff09;Easyexcel&#xff08;4-模板文件&#xff09;Easyexcel&#xff08;5-自定义列宽&#xff09;Easyexcel&#xff08;6-单…

通用网络安全设备之【防火墙】

概念&#xff1a; 防火墙&#xff08;Firewall&#xff09;&#xff0c;也称防护墙&#xff0c;它是一种位于内部网络与外部网络之间的网络安全防护系统&#xff0c;是一种隔离技术&#xff0c;允许或是限制传输的数据通过。 基于 TCP/IP 协议&#xff0c;主要分为主机型防火…

对于GC方面,在使用Elasticsearch时要注意什么?

大家好&#xff0c;我是锋哥。今天分享关于【对于GC方面&#xff0c;在使用Elasticsearch时要注意什么&#xff1f;】面试题。希望对大家有帮助&#xff1b; 对于GC方面&#xff0c;在使用Elasticsearch时要注意什么&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java…

[仓颉Cangjie刷题模板] 优先队列(含小顶堆实现)

[TOC]([仓颉Cangjie刷题模板] 优先队列(含小顶堆实现) ) 一、 算法&数据结构 1. 描述 堆是一个可以维护实时最大/最小值的数据结构&#xff0c;相比treeset等常数优很多。 常用于维护一组数据的极值贪心问题。2. 复杂度分析 初始化O(n)查询O(1)修改O(lgn) 3. 常见应用…

解决 MySQL 5.7 安装中的常见问题及解决方案

目录 前言1. 安装MySQL 5.7时的常见错误分析1.1 错误原因及表现1.2 错误的根源 2. 解决方案2.1 修改YUM仓库配置2.2 重新尝试安装2.3 处理GPG密钥错误2.4 解决依赖包问题 3. 安装成功后的配置3.1 启动MySQL服务3.2 获取临时密码3.3 修改root密码 4. 结语 前言 在Linux服务器上…

计算机网络 网络安全基础——针对实习面试

目录 网络安全基础你了解被动攻击吗&#xff1f;你了解主动攻击吗&#xff1f;你了解病毒吗&#xff1f;说说基本的防护措施和安全策略&#xff1f; 网络安全基础 网络安全威胁是指任何可能对网络系统造成损害的行为或事件。这些威胁可以是被动的&#xff0c;也可以是主动的。…

oracle小技巧-解决特殊密码字符而导致的exp错误

在使用oracle数据库的时候&#xff0c;我们经常会利用exp工具对某些表进行导出。但有些时候&#xff0c;因我们用户密码为安全性设有特殊字符&#xff0c;导致exp导出时候报&#xff1a;“EXP-00056和ORA-12154”&#xff0c;今天我们就分享下如何通过设置符号隔离的小技巧解决…

Taro 鸿蒙技术内幕系列(三) - 多语言场景下的通用事件系统设计

基于 Taro 打造的京东鸿蒙 APP 已跟随鸿蒙 Next 系统公测&#xff0c;本系列文章将深入解析 Taro 如何实现使用 React 开发高性能鸿蒙应用的技术内幕 背景 在鸿蒙生态系统中&#xff0c;虽然原生应用通常基于 ArkTS 实现&#xff0c;但在实际研发过程中发现&#xff0c;使用 C…

带有悬浮窗功能的Android应用

android api29 gradle 8.9 要求 布局文件 (floating_window_layout.xml): 增加、删除、关闭按钮默认隐藏。使用“开始”按钮来控制这些按钮的显示和隐藏。 服务类 (FloatingWindowService.kt): 实现“开始”按钮的功能&#xff0c;点击时切换增加、删除、关闭按钮的可见性。处…

ML 系列:第 36 节 — 统计学中的抽样类型

ML 系列&#xff1a;第 36 天 — 统计学中的抽样类型 文章目录 一、说明二、抽样方法三、简单随机抽样四、 Stratified Sampling分层抽样五、 Cluster Sampling 整群抽样六、Systematic Sampling系统抽样七、Convenience Sampling便利抽样八、结论 一、说明 统计学中的抽样类型…

CGMA – Cloth Creation and Simulation for Real-Time

CGMA – 实时布料创建和模拟 Info&#xff1a; 本课程介绍如何将 Marvelous Designer 整合到布料工作流程中以实时创建角色&#xff0c;从软件基础知识到创建逼真和风格化服装的高级技术。本课程将首先介绍软件&#xff0c;通过创建现代、现代的服装&#xff0c;然后深入探讨使…

Springboot组合SpringSecurity安全插件基于密码的验证Demo

Springboot组合SpringSecurity安全插件基于密码的验证Demo!下面的案例&#xff0c;都是基于数据库mysql&#xff0c;用户密码&#xff0c;验证登录的策略demo。 1&#xff1b;引入maven仓库的坐标 <dependency><groupId>org.springframework.boot</groupId>…

从Full-Text Search全文检索到RAG检索增强

从Full-Text Search全文检索到RAG检索增强 时光飞逝&#xff0c;转眼间六年过去了&#xff0c;六年前铁蛋优化单表千万级数据查询性能的场景依然历历在目&#xff0c;铁蛋也从最开始做CRUD转行去了大数据平台开发&#xff0c;混迹包装开源的业务&#xff0c;机缘巧合下做了实时…

单片机学习笔记 8. 矩阵键盘按键检测

更多单片机学习笔记&#xff1a;单片机学习笔记 1. 点亮一个LED灯单片机学习笔记 2. LED灯闪烁单片机学习笔记 3. LED灯流水灯单片机学习笔记 4. 蜂鸣器滴~滴~滴~单片机学习笔记 5. 数码管静态显示单片机学习笔记 6. 数码管动态显示单片机学习笔记 7. 独立键盘 目录 0、实现的…

【AI日记】24.11.26 聚焦 kaggle 比赛

【AI论文解读】【AI知识点】【AI小项目】【AI战略思考】【AI日记】 核心工作 1 内容&#xff1a;研究 kaggle 比赛时间&#xff1a;3 小时 核心工作 2 内容&#xff1a;学习 kaggle 比赛 Titanic - Machine Learning from Disaster时间&#xff1a;4 小时备注&#xff1a;这…

排序算法2

排序算法1-CSDN博客 排序算法1中提及的是较为基础(暴力实现&#xff0c;复杂度较高)的排序算法&#xff0c;不适合于数据量较大的场景&#xff0c;比如序列长度达到1e5 接下来以蓝桥另一道题目来理解其它的排序算法 蓝桥3226 蓝桥账户中心 样例 5 1 5 9 3 7 4、快速排序 快速排…

【数据结构实战篇】用C语言实现你的私有队列

&#x1f3dd;️专栏&#xff1a;【数据结构实战篇】 &#x1f305;主页&#xff1a;f狐o狸x 在前面的文章中我们用C语言实现了栈的数据结构&#xff0c;本期内容我们将实现队列的数据结构 一、队列的概念 队列&#xff1a;只允许在一端进行插入数据操作&#xff0c;在另一端…

macos 14.0 Monoma 修改顶部菜单栏颜色

macos 14.0 设置暗色后顶部菜单栏还维持浅色&#xff0c;与整体不协调。 修改方式如下&#xff1a;