C语言课程回顾:十二、C语言之 位运算

12 位运算

前面介绍的各种运算都是以字节作为最基本位进行的。 但在很多系统程序中常要求在位(bit)一级进行运算或处理。C语言提供了位运算的功能,这使得C语言也能像汇编语言一样用来编写系统程序。

12.1 位运算符C语言提供了六种位运算符:

&          按位与
|          按位或
^          按位异或
~          取反
<<         左移
>>         右移

12.1.1 按位与运算

按位与运算符"&"是双目运算符。其功能是参与运算的两数各对应的二进位相与。只有对应的两个二进位均为1时,结果位才为1,否则为0。参与运算的数以补码方式出现。

例如:9&5可写算式如下:
00001001 (9的二进制补码)
&00000101 (5的二进制补码)
00000001 (1的二进制补码)
可见9&5=1。
按位与运算通常用来对某些位清0或保留某些位。例如把a 的高八位清 0 ,保留低八位,可作a&255运算( 255 的二进制数为0000000011111111)。
【例12.1】

main(){int a=9,b=5,c;c=a&b;printf("a=%d\nb=%d\nc=%d\n",a,b,c);
}

12.1.2 按位或运算

按位或运算符“|”是双目运算符。其功能是参与运算的两数各对应的二进位相或。只要对应的二个二进位有一个为1时,结果位就为1。参与运算的两个数均以补码出现。
例如:9|5可写算式如下:
00001001
|00000101
00001101 (十进制为13)可见9|5=13
【例12.2】

main(){int a=9,b=5,c;c=a|b;printf("a=%d\nb=%d\nc=%d\n",a,b,c);
}

12.1.3 按位异或运算

按位异或运算符“”是双目运算符。其功能是参与运算的两数各对应的二进位相异或,当两对应的二进位相异时,结果为1。参与运算数仍以补码出现,例如95可写成算式如下:
00001001
^00000101
00001100 (十进制为12)
【例12.3】

main(){int a=9;a=a^5;printf("a=%d\n",a);
}

12.1.4 求反运算

求反运算符~为单目运算符,具有右结合性。其功能是对参与运算的数的各二进位按位求反。
例如~9的运算为:
~(0000000000001001)结果为:1111111111110110
12.1.5 左移运算
左移运算符“<<”是双目运算符。其功能把“<< ”左边的运算数的各二进位全部左移若干位,由“<<”右边的数指定移动的位数,高位丢弃,低位补0。
例如:
a<<4
指把a的各二进位向左移动4位。如a=00000011(十进制3),左移4位后为00110000(十进制48)。
12.1.6 右移运算
右移运算符“>>”是双目运算符。其功能是把“>> ”左边的运算数的各二进位全部右移若干位,“>>”右边的数指定移动的位数。
例如:
设 a=15,
a>>2
表示把000001111右移为00000011(十进制3)。
应该说明的是,对于有符号数,在右移时,符号位将随同移动。当为正数时,最高位补0,而为负数时,符号位为1,最高位是补0或是补1 取决于编译系统的规定。Turbo C和很多系统规定为补1。
【例12.4】

main(){unsigned a,b;printf("input a number:   ");scanf("%d",&a);b=a>>5;b=b&15;printf("a=%d\tb=%d\n",a,b);
}

请再看一例!
【例12.5】

main(){char a='a',b='b';int p,c,d;p=a;p=(p<<8)|b;d=p&0xff;c=(p&0xff00)>>8;printf("a=%d\nb=%d\nc=%d\nd=%d\n",a,b,c,d);
}

12.2 位域(位段)

有些信息在存储时,并不需要占用一个完整的字节,而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1两种状态,用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。
所谓“位域”是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。

  1. 位域的定义和位域变量的说明
    位域定义与结构定义相仿,其形式为:
    struct 位域结构名
    { 位域列表 };
    其中位域列表的形式为:
    类型说明符 位域名:位域长度
    例如:
struct bs{int a:8;int b:2;int c:6;};

位域变量的说明与结构变量说明的方式相同。 可采用先定义后说明,同时定义说明或者直接说明这三种方式。
例如:

struct bs{int a:8;int b:2;int c:6;}data;

说明data为bs变量,共占两个字节。其中位域a占8位,位域b占2位,位域c占6位。
对于位域的定义尚有以下几点说明:

  1. 一个位域必须存储在同一个字节中,不能跨两个字节。如一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域。也可以有意使某位域从下一单元开始。
    例如:
struct bs{unsigned a:4unsigned :0        /*空域*/unsigned b:4       /*从下一单元开始存放*/unsigned c:4}
在这个位域定义中,a占第一字节的4位,后4位填0表示不使用,b从第二字节开始,占用4位,c占用4位。
  1. 由于位域不允许跨两个字节,因此位域的长度不能大于一个字节的长度,也就是说不能超过8位二进位。
  2. 位域可以无位域名,这时它只用来作填充或调整位置。无名的位域是不能使用的。例如:
struct k{int a:1int  :2          /*该2位不能使用*/int b:3int c:2};

从以上分析可以看出,位域在本质上就是一种结构类型,不过其成员是按二进位分配的。
2. 位域的使用
位域的使用和结构成员的使用相同,其一般形式为:
位域变量名•位域名
位域允许用各种格式输出。
【例12.6】

main(){struct bs{unsigned a:1;unsigned b:3;unsigned c:4;} bit,*pbit;bit.a=1;bit.b=7;bit.c=15;printf("%d,%d,%d\n",bit.a,bit.b,bit.c);pbit=&bit;pbit->a=0;pbit->b&=3;pbit->c|=1;printf("%d,%d,%d\n",pbit->a,pbit->b,pbit->c);
}

上例程序中定义了位域结构bs,三个位域为a,b,c。说明了bs类型的变量bit和指向bs类型的指针变量pbit。这表示位域也是可以使用指针的。程序的9、10、11三行分别给三个位域赋值(应注意赋值不能超过该位域的允许范围)。程序第12行以整型量格式输出三个域的内容。第13行把位域变量bit的地址送给指针变量pbit。第14行用指针方式给位域a重新赋值,赋为0。第15行使用了复合的位运算符"&=“,该行相当于:
pbit->b=pbit->b&3
位域b中原有值为7,与3作按位与运算的结果为3(111&011=011,十进制值为3)。同样,程序第16行中使用了复合位运算符”|=",相当于:
pbit->c=pbit->c|1
其结果为15。程序第17行用指针方式输出了这三个域的值。

12.3 位运算的实际应用

设置位
要设置某一位为1,可以使用按位或运算符|和一个合适的位掩码。例如,要将整数a的第3位置1:

int a = 5;  // 二进制: 0101
int mask = 1 << 2;  // 二进制: 0100
a = a | mask;  // 结果: 0111 (即7)

清除位
要清除某一位为0,可以使用按位与运算符&和一个取反的位掩码。例如,要将整数a的第3位清0:

int a = 7;  // 二进制: 0111
int mask = ~(1 << 2);  // 二进制: 1011
a = a & mask;  // 结果: 0011 (即3)

切换位
要切换某一位(0变1,1变0),可以使用按位异或运算符^和一个合适的位掩码。例如,要切换整数a的第3位:

int a = 5;  // 二进制: 0101
int mask = 1 << 2;  // 二进制: 0100
a = a ^ mask;  // 结果: 0001 (即1)

检查位
要检查某一位是0还是1,可以使用按位与运算符&和一个合适的位掩码。例如,要检查整数a的第3位是否为1:

int a = 5;  // 二进制: 0101
int mask = 1 << 2;  // 二进制: 0100
int result = a & mask;  // 结果: 0000 (即0,表示第3位为0)

高级位运算技巧
位域
位域(bit field)是一种在结构体中定义位段的小技巧。位域允许我们以更紧凑的方式存储数据。例如:

struct {unsigned int a : 1;unsigned int b : 3;unsigned int c : 4;
} bitfields;bitfields.a = 1;
bitfields.b = 5;
bitfields.c = 12;

用位运算实现加减乘除
位运算可以用来实现一些基本的数学运算,虽然这些实现方法通常并不常见,但它们可以提高某些情况下的性能。

加法
加法可以通过位运算来实现,使用按位异或和按位与运算:

int add(int x, int y) {while (y != 0) {int carry = x & y;x = x ^ y;y = carry << 1;}return x;
}

乘法
乘法可以通过位移和加法来实现:

int multiply(int x, int y) {int result = 0;while (y != 0) {if (y & 1) {result = add(result, x);}x <<= 1;y >>= 1;}return result;
}

除法
除法可以通过减法和位移来实现:

int divide(int dividend, int divisor) {int sign = ((dividend < 0) ^ (divisor < 0)) ? -1 : 1;dividend = abs(dividend);divisor = abs(divisor);int quotient = 0;while (dividend >= divisor) {dividend -= divisor;quotient++;}return sign * quotient;
}

12.4位运算注意事项

在深入探讨位运算的注意事项之前,我们先简要回顾一下位运算的基本概念和常见操作。

1 二进制和位

计算机内部使用二进制系统表示数据。二进制系统只有两个数字:0和1。每个数字称为“位”(bit)。一个字节(byte)由8个位组成,因此可以表示从0到255的值。

2 位运算符

C语言提供了几种位运算符,用于直接操作二进制位。以下是C语言中的位运算符:

按位与:&
按位或:|
按位异或:^
按位取反:~
左移:<<
右移:>>
这些运算符能够对数据的每个位进行直接操作,从而实现高效的数据处理。

3常见位运算操作和注意事项

按位与(&)
按位与运算会将两个操作数的对应位进行比较,如果两个位都是1,则结果位为1,否则为0。

注意事项:

用于位掩码:按位与常用于位掩码操作,用于清除某些位或检查某些位是否为1。在使用位掩码时,需要确保掩码的正确性,否则可能导致意外的结果。
避免混淆与逻辑与:按位与&与逻辑与&&不同,后者用于布尔逻辑操作。要避免在需要逻辑与的地方使用按位与。

int a = 5;  // 二进制: 0101
int b = 3;  // 二进制: 0011
int c = a & b;  // 结果: 0001 (即1)

按位或(|)
按位或运算会将两个操作数的对应位进行比较,如果两个位中有一个是1,则结果位为1,否则为0。

注意事项:

用于设置位:按位或常用于设置某些位为1。在使用时,需要确保只设置需要的位,避免误操作。
避免混淆与逻辑或:按位或|与逻辑或||不同,后者用于布尔逻辑操作。要避免在需要逻辑或的地方使用按位或。

int a = 5;  // 二进制: 0101
int b = 3;  // 二进制: 0011
int c = a | b;  // 结果: 0111 (即7)

按位异或(^)
按位异或运算会将两个操作数的对应位进行比较,如果两个位不相同,则结果位为1,否则为0。

注意事项:

用于切换位:按位异或常用于切换某些位(0变1,1变0)。在使用时,需要确保切换的位是需要操作的部分。
避免误用:按位异或^有时会被误认为是幂运算符。在C语言中,幂运算需要使用库函数pow。

int a = 5;  // 二进制: 0101
int b = 3;  // 二进制: 0011
int c = a ^ b;  // 结果: 0110 (即6)

按位取反(~)
按位取反运算会将操作数的每个位进行翻转,即0变为1,1变为0。

注意事项:

符号位处理:对于有符号数,按位取反会影响符号位,可能导致负数的产生。在处理有符号数时需要特别小心。
应用场景:按位取反主要用于生成位掩码或快速求补运算。在实际应用中需要确保操作数的正确性。

int a = 5;  // 二进制: 00000000 00000000 00000000 00000101
int b = ~a;  // 结果: 11111111 11111111 11111111 11111010 (即-6)

2.5 左移(<<)
左移运算会将操作数的位向左移动指定的位数,右侧补0。

注意事项:

溢出风险:左移操作可能导致溢出,尤其是在移位数大于或等于数据类型的位数时。需要确保移位数在合理范围内。
符号位处理:对于有符号数,左移操作不会改变符号位,但可能导致数值变化。在处理有符号数时需要特别小心。

int a = 5;  // 二进制: 00000101
int b = a << 1;  // 结果: 00001010 (即10)

2.6 右移(>>)
右移运算会将操作数的位向右移动指定的位数,左侧补0或符号位(取决于操作数是有符号数还是无符号数)。

注意事项:

算术右移和逻辑右移:对于有符号数,右移操作可能是算术右移(保留符号位)或逻辑右移(填充0)。在不同编译器和平台上可能有所不同,需要仔细确认。
避免负数操作:对于有符号数,右移操作可能会导致意外的结果,尤其是负数。因此在右移有符号数时需要特别小心。

int a = 5;  // 二进制: 00000101
int b = a >> 1;  // 结果: 00000010 (即2)

4 应用场景和实践

位掩码的使用
位掩码在位运算中非常常用,通常用于清除、设置或切换特定位。

注意事项:

正确设计掩码:位掩码的设计需要符合操作需求,避免误操作。例如,要清除某些位时,掩码需要取反。
避免重复操作:在使用位掩码时,避免重复操作相同的位,可能导致不可预期的结果。

int a = 5;  // 二进制: 0101
int mask = 1 << 2;  // 二进制: 0100
a = a | mask;  // 设置第3位为1,结果: 0111 (即7)

位域的使用
位域(bit field)是一种在结构体中定义位段的小技巧。位域允许我们以更紧凑的方式存储数据。

注意事项:

对齐问题:位域在不同编译器和平台上可能有不同的对齐方式,使用时需要注意避免对齐问题导致的数据错乱。
可移植性:位域的实现细节在不同编译器上可能有所不同,使用位域时需要特别注意程序的可移植性。

struct {unsigned int a : 1;unsigned int b : 3;unsigned int c : 4;
} bitfields;bitfields.a = 1;
bitfields.b = 5;
bitfields.c = 12;

用位运算实现数学运算
位运算可以用来实现一些基本的数学运算,虽然这些实现方法通常并不常见,但它们可以提高某些情况下的性能。

注意事项:

复杂性:用位运算实现数学运算可能增加代码的复杂性,阅读和维护难度较大。在性能不敏感的情况下,优先选择更易理解的实现方式。
正确性:确保位运算实现的数学运算结果正确,避免因位运算错误导致的计算错误。
加法

int add(int x, int y) {while (y != 0) {int carry = x & y;x = x ^ y;y = carry << 1;}return x;
}

乘法

int multiply(int x, int y) {int result = 0;while (y != 0) {if (y & 1) {result = add(result, x);}x <<= 1;y >>= 1;}return result;
}

除法

int divide(int dividend, int divisor) {int sign = ((dividend < 0) ^ (divisor < 0)) ? -1 : 1;dividend = abs(dividend);divisor = abs(divisor);int quotient = 0;while (dividend >= divisor) {dividend -= divisor;quotient++;}return sign * quotient;
}

5 性能优化

避免多余的位运算
在进行位运算时,尽量避免多余的操作,减少不必要的计算量。例如,在循环中避免重复计算相同的位掩码。

注意事项:

缓存计算结果:对于需要重复使用的位掩码或移位结果,尽可能缓存计算结果,避免重复计算。
优化逻辑:合理设计位运算逻辑,尽量减少不必要的操作,提高执行效率。
使用内置函数
一些编译器提供了内置的位运算相关函数,这些函数通常经过优化,性能优于手写的位运算代码。例如,GCC提供了__builtin_popcount用于计算二进制数中1的个数。

注意事项:

了解编译器支持:在使用内置函数前,需要了解所使用编译器是否支持这些函数,并确保程序的可移植性。
合理使用:在性能敏感的场合,优先考虑使用内置函数进行优化,但在一般场合下,保持代码的可读性更为重要。
避免位运算陷阱
在使用位运算时,需要特别注意一些常见的陷阱和误区,避免因误操作导致的程序错误。

注意事项:

操作数类型:确保位运算的操作数类型一致,避免因类型不匹配导致的位运算错误。例如,有符号数和无符号数混用可能导致不可预期的结果。
边界条件:在进行移位操作时,注意边界条件,避免移位数超出数据类型的位数。例如,对于32位整数,移位数应在0到31之间。
溢出和下溢:位运算可能导致数据溢出或下溢,需要特别注意操作数范围,确保结果在合理范围内。

6 调试和测试

位运算的调试和测试相对复杂,需要特别注意一些细节,确保程序的正确性。
使用调试工具
在调试位运算代码时,可以借助调试工具,如GDB,查看每一步操作的结果,确保运算过程符合预期。

注意事项:

逐步调试:逐步调试位运算代码,查看每一步操作的结果,确保每个位的操作正确。
观察变量值:使用调试工具观察变量的二进制表示,确保位运算结果符合预期。
编写单元测试
编写单元测试对位运算代码进行全面测试,确保每种情况都能正确处理。

注意事项:

覆盖所有情况:单元测试应覆盖所有可能的情况,包括边界条件和特殊情况,确保位运算代码的健壮性。
使用断言:在单元测试中使用断言,验证每一步操作的结果,确保程序逻辑正确。
总结
位运算在C语言中是一项非常强大的技术,能够高效地处理数据。然而,在使用位运算时需要特别注意一些细节,避免因误操作导致的程序错误。本文详细介绍了位运算的基本概念、常见操作、应用场景和注意事项,并提供了一些性能优化和调试测试的建议。希望对你在使用C语言进行位运算时有所帮助。

12.5 小结

位运算是C语言中非常强大的工具,能够高效地进行数据处理。在本文中,我们详细介绍了位运算的基本概念、常见操作和实际应用,并展示了一些高级技巧。熟练掌握位运算,可以帮助你在编写高效、紧凑的代码方面大有裨益。希望本文对你在学习和使用C语言位运算方面有所帮助。

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

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

相关文章

2.9.GoogLeNet

GoogLeNet ​ 主要解决了什么样大小的卷积核是最合适的&#xff1a;有时使用不同大小的卷积核组合是有利的 1.Inception块 ​ Inception块由四条并行路径组成。 前三条路径使用窗口大小为11、33和55的卷积层&#xff0c;从不同空间大小中提取信息。 ​ 中间的两条路径在输入…

谷粒商城实战-58-商品服务-API-三级分类-删除-批量删除小结

文章目录 一&#xff0c;增加一个批量删除的按钮并绑定事件二&#xff0c;全栈工程师三&#xff0c;逆向工程在全栈开发中的应用提升效率的方式&#xff1a;使用案例&#xff1a; 这一节的主要内容是开发批量删除分类的功能。 一&#xff0c;增加一个批量删除的按钮并绑定事件 …

zh echarts样式

记录一下&#xff1a; 一个图的配置 在echarts官网demo界面 option {title: {text: },legend: {data: [xxx前, xxx后]},radar: {// shape: circle,name: {// 雷达图各类别名称文本颜色textStyle: {color: #000,fontSize: 16}},indicator: [{ name: 完整性, max: 1 },{ name:…

【无标题】shell脚本的基本命令+编写shell脚本

shell脚本 一.shell基础 1.shell概念 2.shell脚本 3.shell脚本编写注意事项 二.编写shell脚本 1.编写一个helloworld脚本&#xff0c;运行脚本 [rootshell ~]# vim helloworld.sh #!/bin/bash //声明 echo "hello world!" ls -lh /etc/ 运行脚本(四种方式)&…

图像处理 -- Sensor与ISP驱动之像素时钟获取的方法

像素时钟获取方法 像素时钟&#xff08;Pixel Clock&#xff0c;也称为 PCLK&#xff09;是摄像头 sensor 和 ISP 协调工作时的关键参数之一&#xff0c;决定了每个像素的传输速率。获取或计算像素时钟可以通过以下几种方法&#xff1a; 1. 数据手册 (Datasheet) 大多数摄像…

C语言字符函数与字符串函数超详解

文章目录 前言1. 字符分类函数2. 字符转换函数3. strlen3. 1 strlen 的使用3. 2 strlen 的模拟实现 4. strcpy4. 1 strcpy 的使用4. 2 strcpy 的模拟实现 5. strcat5. 1 strcat 的使用5. 2 strcat 的模拟实现 6. strcmp6. 1 strcmp 的使用6. 2 strcmp 的模拟实现 7. strncpy 函…

VI/VIM编辑器及三种模式

目录 1. 三种模式 2. 使用 VIM 3. i/ a/ o 进入输入模式 VI/VIM是 visual interface 的缩写是 Linux 中最经典的文本编辑器&#xff1b; VIM是 VI 的增强版本&#xff0c;兼容 VI 的所有指令&#xff0c;不仅能够编辑文本&#xff0c;还具有 shell 程序编辑的功能&#xff…

maven引入了jar包但在class文件里找不到jar包里的类

在工作当中遇到的这个问题&#xff0c;别人引入的jar包&#xff0c;我代码里报错 maven clean 和 maven install 都不管用 检查过了pom文件 检查了maven仓库路径下是否有这个cn.hutool的jar包 都没有找到问题 最终解决办法是手动引入 步骤一&#xff1a;点击左上角file->…

3.4-GRU

1网络结构 1.1与LSTM相比 LSTM里面有三个门&#xff0c;还有一个增加信息的tanh单元&#xff0c;参数量相较于RNN显著增加&#xff1b; 因此GRU在参数上比LSTM要少&#xff1b; 另外&#xff0c;LSTM 将必要信息记录在记忆单元中&#xff0c;并基于记忆单元的信息计算隐藏状…

MySQL数据库(基础篇)

&#x1f30f;个人博客主页&#xff1a;心.c 前言&#xff1a;今天讲解的是MySQL的详细知识点的&#xff0c;希望大家可以收货满满&#xff0c;话不多说&#xff0c;直接开始搞&#xff01; &#x1f525;&#x1f525;&#x1f525;文章专题&#xff1a;MySQL &#x1f63d;感…

1.c#(winform)编程环境安装

目录 安装vs创建应用帮助查看器安装与使用&#xff08; msdn&#xff09; 安装vs 安装什么版本看个人心情&#xff0c;或者公司开发需求需要 而本栏全程使用vs2022进行开发c#&#xff0c;着重讲解winform桌面应用开发 使用***.net framework***开发 那先去官网安装企业版的vs…

Python可重入锁RLock的使用

Python可重入锁RLock的使用 在Python中,RLock(即可重入锁)是一种特殊类型的锁,它允许一个线程多次请求同一把锁,而不会造成死锁。这在某些复杂的多线程程序中非常有用,特别是当线程在执行一个函数时需要调用另一个需要相同锁的函数时。 使用 RLock 的基本方法 导入 RLo…

AI绘画入门实践 | Midjourney:使用 --chaos 给图像风格来点惊喜

在 Midjourney 中&#xff0c;--chaos 影响初始图像网格的多样性&#xff0c;指 MJ 每次出的4张图之间的差异性。 默认值为0&#xff0c;值越高&#xff0c;差异性越大。 使用格式&#xff1a;--chaos 0-100的整数值 使用演示 a lot of flowers --chaos 0 --v 6.0a lot of fl…

SSAN代码解析

文章目录 run_docred.py详细介绍每一行代码 dataset.py详细介绍每一行代码输入和输出示例 docred_convert_examples_to_features详细介绍每一行代码 DocREDProcessor详细介绍每一行代码输入和输出 run_docred.py 下面是带有详细中文注释的代码说明&#xff0c;包括输入和输出的…

项目打包与运行

前端运行时必须有与后端相同的数据库版本&#xff0c;数据库账号密码 右侧maven -> 展开要打包的项目 -> 生命周期 -> 双击package 打包好之后在target目录下 右键打开 在资源目录下输入cmd&#xff0c;执行以下命令即可运行&#xff08;端口号为yml文件…

Redis实战篇(黑马点评)笔记总结

一、配置前后端项目的初始环境 前端&#xff1a; 对前端项目在cmd中进行start nginx.exe&#xff0c;端口号为8080 后端&#xff1a; 配置mysql数据库的url 和 redis 的url 和 导入数据库数据 二、登录校验 基于Session的实现登录&#xff08;不推荐&#xff09; &#xf…

【iOS】—— retain\release实现原理和属性关键字

【iOS】—— retain\release实现原理和属性关键字 1. retain\reelase实现原理1.1 retain实现原理1.2 release实现原理 2. 属性关键字2.1 属性关键字的分类2.2 内存管理关键字2.2.1 weak2.2.2 assgin2.3.3 strong和copy 2.4 线程安全的关键字2.5 修饰变量的关键字2.5.1常量const…

文件上传总结

一、原理 通过界面上的上传功能上传了一个可执行的脚本文件&#xff0c;而WEB端的系统并未对其进行检测或者检测的逻辑做的不够好&#xff0c;使得恶意用户可以通过文件中上传的一句话木马获得操控权 二、绕过方法 1>前端绕过 1.删除前端校验函数 checkFile() 2.禁用js…

大数据平台之HBase

HBase是一个高可靠性、高性能、面向列、可伸缩的分布式存储系统&#xff0c;是Apache Hadoop生态系统的重要组成部分。它特别适合大规模结构化和半结构化数据的存储和检索&#xff0c;能够处理实时读写和批处理工作负载。以下是对HBase的详细介绍。 1. 核心概念 1.1 表&#x…

打造一篇完美的【数学建模竞赛论文】:从准备到撰写的全面指南

目录 一、赛前准备 1.1 报名与纪律要求 1.2 MD5码上传 1.3 竞赛准备 1.4 时间分配 二、论文格式规范 2.1 摘要 2.2 参考文献 2.3 排版要求 三、建模过程与方法 3.1 问题分析与模型假设 3.2 模型构建与求解 3.3 结果分析与检验 四、论文撰写技巧 4.1 论文结构 4…