C 语言提取位2025年1月7日 | 阅读13分钟 位操作是编程中的一个基本方面,尤其是在系统编程、嵌入式系统和对性能要求严格的应用中。位操作的一个常见操作是从数据中提取特定位。在 C 编程语言中,使用位运算符可以高效地处理位提取,使程序员能够直接与数据的二进制表示进行交互。此操作对于解析二进制文件格式、管理硬件寄存器、优化数据存储和实现加密算法等任务至关重要。 从本质上讲,位提取涉及在整数或类似数据类型中隔离特定位。最基本形式的此操作是提取单个位,这可以通过按位移位('>>')和按位 AND('&')操作的组合来实现。例如,要确定数字中某个特定位的值,可以使用按位移位运算符将目标位移动到最低有效位位置,然后与 '1' 进行 AND 操作以隔离该位的值。 更复杂的情况涉及提取多个位,通常是连续的位,以从数据字中获取子字段。这在网络中很常见,数据包中的标头包含打包在二进制结构中的各种字段。在这里,可以使用掩码来清除不需要的位,只留下感兴趣的位。通过将所需的低位设置为 '1' 并移位数据后应用按位 AND 操作来创建此掩码。 C 语言中的位操作不仅仅是访问或修改低级别数据;它还涉及效率和可移植性的考虑。例如,字节序(数据存储的字节顺序)会影响位如何被提取和解释,尤其是在具有不同硬件架构的系统中。因此,对底层硬件的透彻理解和对数据表示的仔细处理至关重要。 方法一:位运算提取单个位要从整数中的特定位置提取单个位,我们使用按位右移('>>')和按位 AND('&')操作的组合。 程序输出 Extracting single Bit: Number: 172 (Binary: %08b), Position: 172 Shifted Number: 21 (Binary: %08b) Extracted Bit: 1 Extracting single Bit: Number: 218 (Binary: %08b), Position: 218 Shifted Number: 6 (Binary: %08b) Extracted Bit: 0 Extracting multiple bits: Number: 172 (Binary: %08b), Start: 172, Number of Bits: 2 Mask: 15 (Binary: %08b) Shifted Number: 43 (Binary: %08b) Extracted Bits: 11 (Binary: %04b) Extracting multiple bits: Number: 218 (Binary: %08b), Start: 218, Number of Bits: 1 Mask: 7 (Binary: %08b) Shifted Number: 109 (Binary: %08b) Extracted Bits: 5 (Binary: %03b) Results: Single Bit from number1 at position 3: 1 Single Bit from number2 at position 5: 0 4 Bits from number1 starting at position 2: 11 3 Bits from number2 starting at position 1: 5 说明提供的 C 代码演示了使用位运算从整数中提取单个位和多个位。它包含两个主要函数:一个用于提取单个位,另一个用于提取多个位,并提供类似日志的输出以显示这些操作的内部状态和结果。
复杂度分析时间复杂度 时间复杂度衡量代码执行的操作数与输入大小的关系。在这种情况下,输入大小与整数中的位数有关。 提取单个位 函数 extract_single_bit(int number, int position) 涉及 右移操作('>>'):此操作将整数的位向右移位。右移操作的时间复杂度为O(1),因为它是一项基本操作,由处理器以恒定时间执行,与移位的位数无关。 按位 AND 操作('&'):此操作的时间复杂度也为 O(1),因为它只是比较数字和掩码(在这种情况下为 1)的相应位。 提取单个位的总体时间复杂度为 O(1),因为右移和按位AND 操作均以恒定时间执行。 提取多个位 函数 extract_multiple_bits(int number, int start, int num_bits) 涉及 掩码创建:使用 (1 << num_bits) - 1 创建掩码。这涉及位移和减法操作。位移的复杂度为 O(1),因为它取决于处理器的字大小,而不是 num_bits 的实际值。 右移操作('>>'):与单比特提取类似,此操作将整数移位恒定的位数,导致O(1)复杂度。 按位 AND 操作('&'):将掩码应用于移位后的数字以隔离感兴趣的位也是一个 O(1) 操作。 因此,提取多个位的时间复杂度也为 O(1),因为所有操作(按位移位、掩码创建和按位 AND)都是恒定时间操作。 空间复杂度 空间复杂度是指算法所需的内存量与输入大小的关系。 提取单个位 提取单个位的空间复杂度为 O(1),因为只使用了少数几个额外的整数变量(number、position 和 extracted_bit)。这些变量占用恒定的内存空间,与输入大小无关。 提取多个位 同样,提取多个位的空间复杂度也为 O(1)。该函数使用几个整数变量(number、start、num_bits、mask 和 extracted_bits),所有这些变量都占用恒定的内存空间。这些变量的大小不取决于提取的位数或输入整数的大小。 主函数 主函数初始化了几个整数并调用了位提取函数。这些整数和函数调用的内存使用量也为 O(1)。函数本身不创建大量额外的数据结构或分配动态内存,从而确保总体空间复杂度保持恒定。 方法二:C 语言中的联合体进行类型双关C 语言中的联合体是一种特殊的数据结构,它允许不同的数据类型共享同一内存位置。这意味着联合体可以存储不同类型的数据,但一次只能存储一种类型。其最大成员的大小决定了联合体的大小,并且可以随时访问任何成员,根据成员的数据类型解释内存的底层字节。 联合体的这一特性可用于类型双关,这是一种通过不同类型访问或解释相同数据的技术。类型双关在低级编程中特别有用,例如系统编程、嵌入式系统以及处理硬件接口时,其中需要直接操作底层数据表示。 联合体如何工作?在联合体中,所有成员都从相同的内存地址开始,这意味着它们是重叠的。在向一个成员写入后访问另一个成员可能会改变数据的解释,从而提供对组成该值的原始位的视图。 程序输出 Using union to interpret float as int: Float value: 3.141590 Interpreted as integer: 1078530000 Raw bytes: d0 0f 49 40 Using union to interpret int as float: Integer value: 1078530016 Interpreted as float: 3.141594 Raw bytes: e0 0f 49 40 Byte array from float 3.141590: d0 0f 49 40 Float value obtained from a byte array: Float value: 3.141590 说明
复杂度分析时间复杂度 时间复杂度衡量算法或程序运行时间随输入大小的变化情况。 联合体操作 设置和访问联合体成员:像将值赋给联合体成员(data.f = value)和访问联合体成员(data.i 或 data.bytes)这样的操作都是在恒定时间 O(1) 下执行的。这是因为访问联合体的任何成员都涉及直接内存访问,而无需迭代或复杂的操作。 打印操作 打印值:使用 printf 函数输出值。printf 的时间复杂度取决于格式化和输出操作的复杂性。但是,在此代码的上下文中,每个 printf 语句都以恒定时间 O(1) 执行,因为涉及的操作(打印整数、浮点数和字节)很简单,并且不依赖于数据的大小。 字节操作函数 memcpy 函数:memcpy 函数用于在联合体的 bytes 数组和其他变量之间复制字节。其时间复杂度为O(n),其中 n 是复制的字节数。在此代码中,memcpy 始终对固定大小(4 字节)进行操作,因此在实践中复杂度可视为 O(1)。 由联合体操作、printf 和 memcpy 函数执行的所有操作都是恒定时间操作,因为所涉及的数据大小是固定的(联合体成员为 4 字节)。因此,代码的总体时间复杂度为 O(1),这意味着执行时间是恒定的,并且不会随输入大小而扩展,因为操作是在固定大小的数据上执行的。 空间复杂度 空间复杂度衡量程序相对于其输入大小使用的内存量。 联合体存储 DataUnion 联合体包含三个成员(int、float 和 char[4]),但它们共享相同的内存。联合体的大小由其最大成员决定,在本例中为 4 字节(char[4] 数组的大小)。因此,联合体的空间复杂度为O(1),因为所需的内存是恒定且固定的。 临时变量 printFloatAsInt 和 printIntAsFloat 等函数使用恒定的本地变量内存。这些变量所需的空间不取决于输入的大小,因此它们的空间复杂度为 O(1)。 字节数组 转换函数中使用的字节数组(char byteArray[4])是固定大小的(4 字节),因此这些数组所需的空间是恒定的 O(1)。 固定的联合体和临时变量决定了程序的空间复杂度。由于没有执行动态内存分配,并且使用的空间不随输入大小而变化,因此代码的总体空间复杂度为O(1)。 下一个主题如何在 C 中创建静态库 |
我们请求您订阅我们的新闻通讯以获取最新更新。