笔记·二进制的移位运算
河城凌风(kawashiro-ryofu) Lv5

引子

最近有试着用C语言输出自己土豆服务器上NAS的占用情况。环境还是Debian 10。

通过调用statfs.h头文件获取文件系统信息。

我的代码(nasstat2.c):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <stdio.h>
#include <sys/statfs.h>
#include <sys/types.h>


int main(){
struct statfs nas;
if(statfs("/home/nas",&nas) == -1){
printf("Bad FileSystem\n");
}
else{
unsigned long long totalBlocks = nas.f_bsize;
//(Bytes)
unsigned long long totalSize = totalBlocks * nas.f_blocks;
//(GiB)

//套公式换算
size_t totalGSize = (((totalSize / 1024 ) / 1024 ) / 1024);
unsigned long long freeSize = nas.f_bfree*totalBlocks;
size_t freeGSize = (((freeSize / 1024 ) / 1024 ) / 1024 );

double p = ((double)freeGSize / (double)totalGSize) * 100.0;

printf("NAS %dG %0.0f%",totalGSize,p);
putchar('\n');
int blankblock = (int)((p / 100.0) * 16.0);
int sharpblock = 16 - blankblock;

for(int i = 0; i < sharpblock;i++)putchar('|');
for(int i = 0; i < blankblock;i++)putchar(' ');

putchar('\n');
}

return 0;
}

在输出totalGSize(GB单位的挂载点总容量)和p(剩余容量百分比)前,需要对单位进行换算。我选择套公式。

我也参考了其他前辈的的方法,改良后是这样(nasstat3.c):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <sys/statfs.h>
#include <sys/types.h>


int main(){
struct statfs nas;
if(statfs("/home/nas",&nas) == -1){
printf("Bad FileSystem\n");
}
else{
unsigned long long totalBlocks = nas.f_bsize;
//(Bytes)
unsigned long long totalSize = totalBlocks * nas.f_blocks;
//(GiB)
size_t totalGSize = totalSize >> 30;

unsigned long long freeSize = nas.f_bfree*totalBlocks;
size_t freeGSize = freeSize >> 30;

double p = ((double)freeGSize / (double)totalGSize) * 100.0;



printf("NAS %dG %f%\n", totalGSize, p);

int blankblock = (int)((p / 100.0) * 16.0);
int sharpblock = 16 - blankblock;

for(int i = 0; i < sharpblock;i++)putchar('|');
for(int i = 0; i < blankblock;i++)putchar(' ');

putchar('\n');
}

return 0;
}

二者输出的结果几乎没有区别。

输出p时只保留了整数……

image

image


虽然说二进制移位运算这个很容易理解,但我还是没有很好地运用呢,就干脆温习一下吧。

正文

二进制的位运算中,异或取反都和逻辑运算没有多大的区别。

而移位运算也不难理解。

移位运算分为左移右移,对应的运算符分别是<<>>

  • 左移:各二进制位向左移若干位,高位丢弃,低位补0。二进制左移x位后面就加x个0再去掉前面的0
  • 右移:各二进位全部右移若干位,对无符号数,高位补0,有符号数,各编译器处理方法不一样,有的补符号位(算术右移),有的补0(逻辑右移)通常右移x位就在前面加x位0(正数加0,复数加1)并去掉后面x位

例子

左移

0011 0111 << 2 = 1101 1100

0011 0111 << 2

= 00 1101 1100

= 1101 1100

右移

0011 0111 >> 2 = 0000 1101

0011 0111 >> 2

= 0000 1101 11

= 0000 1101


到这里就很好理解了。

$$ \because \left ( 1 \right ) _{10} << 1 = \left ( 1 \right ) {2} << 1 = \left (10 \right ){2} = \left ( 2 \right ) _{10} $$

$$ \left ( 2 \right ) _{10} << 1 = \left ( 10 \right ) {2} << 1 = \left (100 \right ){2} = \left ( 4 \right ) _{10} $$

$$ \left ( 4 \right ) _{10} << 1 = \left ( 100 \right ) {2} << 1 = \left (1000 \right ){2} = \left ( 8 \right ) _{10} $$

$$ \dots $$

$$ \therefore a << 1 = a \times 2 $$

$$ \because \left( 128 \right){10} >> 1 = (1000 0000){2} >> 1 = (1000000){2} = (64){10} $$

$$ \left ( 64 \right ){10} >> 1 = \left ( 1000000 \right ) {2} >> 1 = \left (100000 \right ){2} = \left (32\right ){10} $$

$$ \left ( 32 \right ){10} >> 1 = \left ( 100000 \right ) {2} >> 1 = \left (10000 \right ){2} = \left (16\right ){10} $$

$$ \dots $$

$$ \therefore a >> 1 = \frac{a}{2} $$

左移一个二进制位等同于该数化为十进制后乘以2,右移一个二进制位相当于该数化为十进制后除以2。

末尾

那么前面通过右移30个二进制位将字节换算为GB的方法就没有那么难理解了。

$$ \because 1 KB = 1B \times 1024 $$

$$ 1MB = 1 KB \times 1024 = 1B \times 1024^{2} $$

$$ 1GB = 1MB \times 1024 = 1KB \times 1024^{2} = 1B \times 1024^{3} = 1B \times 1073741824 $$

$$ \therefore 1GB = 1073741824B $$

$$ \because (1073741824 B){10} = (1 \times 10^{30}){2} $$

$$ \therefore (1 \times 10^{30}){2} >> 30 = (1){2} = 1GB $$

(完,又水了一篇)

 评论
评论插件加载失败
正在加载评论插件