如何对于多字节变量进行逐字节读写

本文深入探讨了位操作在编程中的应用,包括如何在指定字节读写数据,以及使用位或和位与操作符进行数据擦除和读取的详细步骤。通过Python实验,展示了位操作的实用性和灵活性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 大部分编程语言都没有直接给我们提供对于位进行操作的方法,有时候为了节约空间或者是实现一些特殊目的,我们需要对于一个存储空间中的某一段 “位串” 进行读写。

目录

向指定字节写入数据

当被写入的空间的二进制位全是0的时候

当被写入的空间的二进制位不是全是0的时候

从指定字节读取数据

封装好的读写指定字节的python函数

位操作原理总结

规律

写入数据的2种方法

使用 位或 向目标空间的第n位开始写入数据串

使用 位与 向目标空间的第n位开始写入数据串

读取数据的2种方法

使用 位与 来读取目标空间的第n位开始长度为L的数据串

使用 位或 来读取目标空间的第n位开始长度为L的数据串


我们要实现:对于第n字节进行写入数据和读取数据,同时其他3字节的数据不能受影响。

让我们利用Python来做这个实验,为方便表示,我们利用十六进制的表示方法来演示。

1个十六进制位相当于4个二进制位,所以1个字节的8位在十六进制的表示方法里占2个十六进制位,比如 二进制数 11110001 等于十六进制数 f1。

在Python中十六进制数据 f1 用 0xf1 表示。

向指定字节写入数据

当被写入的空间的二进制位全是0的时候

注意,被写入的那一字节空间在写入前必须是全0!

例如:我们有一个int类型的4字节数据

a = 0xab120056

让我们从二进制的角度来考虑,它的第二字节为全为0,我们要向它的第二字节写入数据 0x34

关键一步来了,我们要构造另一个int类型数据,其第二字节的数据是我们想要写入的数据 0x34,其他3字节都是0

我们把这个构造的新int数据叫做掩码

mask = 0x00003400

我们也可以用位的位移操作符 << 来构造这个掩码,只需要将数据位左移指定字节就好,比如我们要移动到第二字节就左移8位,第三字节就左移16位。

mask = 0x34 << 8

获得了包含有我们要写入的数据的掩码后,我们就可以进行写入操作了

我们只需要将被写入的数据和掩码做位或,将得到的值写回被写入的空间就行了

a = a|mask

至此,数据 0x34 已经被写入了int变量a所在的空间的第二字节,并且其他数据没有受到影响

print("a=“,a) # a=0xab123456

 

当被写入的空间的二进制位不是全是0的时候

如果被写入的那一字节在写入前不为全零,我们是不能按上边的方法直接构造掩码并写入的,我们要先将原来的非全零数据进行擦除,即先设法将其全置为零。

让我们对于数据a = 0xab123456的第三字节进行擦除

同样,我们再构造一个和被操作数据等长的掩码,将掩码的要擦除的字节位置全置为0,不希望擦出的字节位置全置为1。

我们要擦除第三字节,就将掩码的第三字节的二进制位全置为0,其余部分全置为1

mask = 0xff00ffff

让我们对于目标的第三字节进行擦除,只需用掩码与被操作的数据进行位与操作,将得到的值覆盖掉原来的值就好

a = a&mask

至此,第三字节的数据已经被擦除,即全置为0,并且其他数据没有受到影响

print("a=“,a) # a=0xab003456

 

擦除后,我们就可以像上边那样对于这一字节进行写入了,不再赘述。

 

从指定字节读取数据

我们已经成功地对于指定字节写入了数据,当我们想使用这些数据的时候,需要把它们读取出来。

假如我们有数据 a=0xab123456

我们想读取其第二字节的数据0x34

我们只需要构造一个这样的掩码,其第二字节二进制位全为1,其余位全为0

mask = 0x0000ff00

我们要读取目标数据的第二字节,只需要使用掩码与目标数据进行位与,再将得到的结果进行右位移,将想要的数据位移到最低位即可

a = a&mask

print("a=“,a) # a=0x00003400

a = a >> 8

print("a=“,a) # a=0x00000034

 

至此,我们就成功的从指定数据的第二字节读取了数据。

 

封装好的读写指定字节的python函数

def writeByte(var_to, data, which_byte):
    # 构造含有数据的写入掩码
    mask_data = data << (which_byte-1)*8
    # 构造擦除指定字节的擦除掩码
    mask_tozero = ~(0xff << (which_byte-1)*8)
    # 不管要写入的位原来是什么情况,一律先擦除
    var_to =  var_to & mask_tozero
    # 写入数据
    var_to = var_to | mask_data
    return var_to
​
​
def readByte(var_from, which_byte):
    # 构造可以读取指定字节的读取掩码
    mask_read = 0xff << (which_byte-1)*8
    # 读取数据
    data = var_from & mask_read
    # 提取数据
    data = data >> (which_byte-1)*8
    return data
​
# 原始数据
a = 0xab123456
# 写入在第二字节写入数据 0xcd
a = writeByte(a, 0xcd, 2)
# 打印一下
print(hex(a))  # 0xab12cd56
# 读取第二字节的数据
data = readByte(a, 2)
# 打印一下
print(hex(data))  # 0xcd



位操作原理总结

规律

位操作真是一件很神奇的事情,明明就是一些简单的规则(与/或)

  • 0 | 0 = 0

  • 0 | 1 = 1

  • 1 | 1 = 1

  • 0 & 0 = 0

  • 1 & 0 = 0

  • 1 & 1 = 1


如果从另一个角度来看待这些操作,就会有新用法


  • 用0 位或 任何二进制位对方不变

  • 用0 位与 任何二进制位对方变成0

  • 用1 位或 任何二进制位对方变成1

  • 用1 位与 任何二进制位对方不变


将以上特性推广到二进制串

  • 用全0位串 位或 任何二进制位串对方不变 (读取数据)

  • 用全1位串 位与 任何二进制位串对方不变(读取数据)

  • 用全1位串 位或 任何二进制位串对方变成全1(用1填充,和第1条配合用来将指定位置串用1填充而不影响其他位置)

  • 用全0位串 位与 任何二进制位串对方变成全0(用0填充,和第2条配合用来将指定位置串用0填充而不影响其他位置)


  • 用一个01数据串 位或 一个全0位串得到那个01数据串(用来写入数据)

  • 用一个01数据串 位或 一个全1位串得到一个全1串(写入失败……(写入保护))

  • 用一个01数据串 位与 一个全1位串得到那个01数据串(用来写入数据)

  • 用一个01数据串 位与 一个全0位串得到一个全0串(写入失败……(写入保护))

写入数据的2种方法

使用 位或 向目标空间的第n位开始写入数据串

掩码的构造:构造一个和被写入空间等长的全0串,从第n位开始,将要写入的数据放入这个全0串

目标空间:要事先将被写入的位置串全部置0

操作:

  1. 目标空间数据 位或 掩码

  2. 得到的结果再写入目标空间

使用 位与 向目标空间的第n位开始写入数据串

掩码的构造:构造一个和被写入空间等长的全1串,从第n位开始,将要写入的数据放入这个全0串

目标空间:要事先将被写入的位置串全部置1

操作:

  1. 目标空间数据 位与 掩码

  2. 得到的结果再写入目标空间

读取数据的2种方法

使用 位与 来读取目标空间的第n位开始长度为L的数据串

掩码的构造:构造一个和被写入空间等长的全0串,从第n位开始到后边的L为都置1

操作:

  1. 目标空间数据 位与 掩码

  2. 得到的数据再 右位移 ,将数据段位移到最低位,得到想读取的数据。

使用 位或 来读取目标空间的第n位开始长度为L的数据串

掩码1的构造:构造一个和被写入空间等长的全1串,从第n位开始到后边的L为都置0

掩码2的构造:构造一个和被写入空间等长的全0串,从第n位开始到后边的L为都置1

操作:

  1. 目标空间数据 位或 掩码1

  2. 将上一步得到的结果 同 掩码2 进行 位与

  3. 得到的数据再 右位移 ,将数据段位移到最低位,得到想读取的数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值