简体   繁体   English

提取 C 中无符号整数的前 n 位

[英]Extract the first n bits of an unsigned int in C

I want to write a function which extracts the first n bits starting by the MSB of a given uint16.我想编写一个函数来提取从给定 uint16 的 MSB 开始的前 n 位。 I'm working with bitmasks for the first time and haven't found an elegant solution as far.我第一次使用位掩码,到目前为止还没有找到一个优雅的解决方案。 I've written a similar function for the last n bits starting by the LSB which uses a bitmask looking like我已经为 LSB 开始的最后 n 位编写了一个类似的函数,它使用的位掩码看起来像

(1 << n) - 1

and think this works.并认为这有效。

If I have the value 0b1010001100000101 my function creates the bitmask (for n = 3 it looks like 0b111 ) and after that, uses the &-operator to check if the bits are present.如果我有值0b1010001100000101我的函数创建位掩码(对于 n = 3,它看起来像0b111 ),然后使用 &-operator 检查位是否存在。

Which way should I use to get the first n bits?我应该使用哪种方式来获取前 n 位?

I would be really happy if someone explain this to me because I want to understand how it works.如果有人向我解释这一点,我会非常高兴,因为我想了解它是如何工作的。

Thank you!谢谢!

You do not need a mask to extract the most significant bits of an unsigned int : just shift the value right by the width of the type less the number of bits:您不需要掩码来提取unsigned int的最高有效位:只需将值右移类型的宽度减去位数:

#include <stdint.h>

uint16_t extract_msbits(uint16_t x, int n) {
    if (n <= 0)
        return 0;
    else
    if (n < 16)
        return x >> (16 - n);
    else
        return x;
}

If the extracted bits should stay in place, you really mean to mask off the lower bits.如果提取的位应该保留在原位,那么您的真正意思是屏蔽低位。 Here is a solution:这是一个解决方案:

#include <limits.h>

uint16_t mask_msbits(uint16_t x, int n) {
    if (n <= 0)
        return 0;
    else
    if (n < 16)
        return x & (~0U << (16 - n));
    else
        return x;
}

The expression (1 << n) - 1 has undefined behavior if n < 0 or n is greater or equal to 15 if the width of int is 16. For this reason, you should write (1U << n) - 1 to compute a mask for an unsigned int or a uint16_t , but it still fails on 16-bit systems if n is 16 or larger, which might be a valid argument for the function.如果n < 0n大于或等于 15 如果int的宽度为 16,则表达式(1 << n) - 1具有未定义的行为。因此,您应该编写(1U << n) - 1来计算unsigned intuint16_t的掩码,但如果n为 16 或更大,它在 16 位系统上仍然失败,这可能是函数的有效参数。 To avoid this issue, either use a test to compute a mask of 0xFFFF for n == 16 or use (1UL << n) - 1 .为避免此问题,请使用测试为n == 16计算掩码0xFFFF或使用(1UL << n) - 1

A simple solution:一个简单的解决方案:

What you can do is to right shift your uint16_t integral value, by 16 - n bits.您可以做的是将您的uint16_t整数值右移16 - n位。 Thus, only n bits remain.因此,只剩下n位。

Assume you have a type uint16_t and an integral object of this type with value 43558 named x :假设您有一个类型uint16_t和一个此类型的整数对象,其值为43558 ,名为x

uint16_t x = 43558U;

Right shifting by 16 - n bits:右移16 - n位:

x >>= (16U - n);

// Or if you want to keep x intact

uint16_t y = x >> (16U - n);

Will store the first n bits in x .将前n位存储在x中。 However, it will be padded with zeroes.但是,它将用零填充。 Therefore, you need to perform bitwise AND ( & ) to test for the presence of 1 and 0 in this resulting x .因此,您需要执行按位AND ( & ) 来测试生成的x中是否存在10

In case you are learning:如果您正在学习:

  • Read these answers on StackOveflow about grabbing n bits在 StackOveflow 上阅读有关获取n这些答案
  • Read this amazing article on bit manipulation阅读这篇关于位操作的精彩文章

If all you want is to mask off all but the top n bits, you can simply shift right then left:如果您只想屏蔽除前n位之外的所有位,您可以简单地先右移再左移:

#include <assert.h>
#include <stdint.h>

/**
 * @brief Masks all but top `n` bits
 * @param number Input number
 * @param n Number of bits to preserve. Must be >= 0 and <= 16
 * @return Original number with all but the top `n` bits masked off
 */
uint16_t msb_n(uint16_t number, const unsigned n) {
    assert(n <= 16 && "cannot shift more than 16 bits.");
    number >>= (16 - n);
    number <<= (16 - n);
    return number;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM