C / C ++检查是否设置了一位,即int变量


100
int temp = 0x5E; // in binary 0b1011110.

有没有一种方法可以检查temp中的第3位是1还是0,而无需移位和屏蔽。

只是想知道是否为此有一些内置函数,还是我被迫自己编写一个。

Answers:


157

在C语言中,如果要隐藏位操作,可以编写一个宏:

#define CHECK_BIT(var,pos) ((var) & (1<<(pos)))

并以此方式检查右端的 n 位:

CHECK_BIT(temp, n - 1)

在C ++中,可以使用std :: bitset


3
如果您需要一个简单的真值,则应为!!((var)&(1 <<(pos)))。
爱德华-加布里埃尔·蒙蒂亚努(Gabriel Munteanu),2009年

10
@Eduard:在C语言中,一切!= 0都是正确的,那为什么要麻烦呢?1完全一样0.1415
Christoph'Feb

1
如果您使用的是C ++,则可以(应该)编写模板而不是宏。:)
杰夫

2
在C中这很好。但是C ++中的这种宏。那太可怕了,很容易受到虐待。使用std :: bitset
Martin York

5
gh std::bitset,真的吗?当然,与其做一点点的工作(可能还需要一些非常好的模板)来检查单个位,而是使用一个肿的容器(在我的实现中)将每个“位”存储在其他未使用的容器中unsigned long。多么浪费空间!
underscore_d

86

检查是否设置了N位(从0开始):

temp & (1 << N)

没有内置功能。


16
+1表示从0开始,因为我怀疑OP认为基于1的问题,而被接受的答案会使他陷入困境。:)
吉姆·巴克2009年

嗯 为什么从0开始?当我们1 << 0?? 对不起,很困惑。
Danijel'2

6
好的,我知道了。我们从第0位开始,这是1<<0,这是1,没有任何班次(班次0),这是1<<0 == 1
Danijel

27

如果是C ++,我只会使用std :: bitset。简单。直截了当。没有机会犯下愚蠢的错误。

typedef std::bitset<sizeof(int)> IntBits;
bool is_set = IntBits(value).test(position);

还是这么愚蠢

template<unsigned int Exp>
struct pow_2 {
    static const unsigned int value = 2 * pow_2<Exp-1>::value;
};

template<>
struct pow_2<0> {
    static const unsigned int value = 1;
};

template<unsigned int Pos>
bool is_bit_set(unsigned int value)
{
    return (value & pow_2<Pos>::value) != 0;
} 

bool result = is_bit_set<2>(value);

4
@ user21714我猜你的意思是std :: bitset <8 * sizeof(int)>
iNFINITEi 2013年

或std :: numeric_limits <int>的::位数
莱奥榄

@iNFINITEi std::bitset<CHAR_BIT * sizeof(int)>更正确
Xeverous

13

是的,我知道我没有这样做”的习惯。但是我通常写:

    /* Return type (8/16/32/64 int size) is specified by argument size. */
template<class TYPE> inline TYPE BIT(const TYPE & x)
{ return TYPE(1) << x; }

template<class TYPE> inline bool IsBitSet(const TYPE & x, const TYPE & y)
{ return 0 != (x & y); }

例如:

IsBitSet( foo, BIT(3) | BIT(6) );  // Checks if Bit 3 OR 6 is set.

除其他外,这种方法:

  • 容纳8/16/32/64位整数。
  • 未经我的知情并检测IsBitSet(int32,int64)调用。
  • 内联模板,因此没有函数调用开销。
  • 常量和参考,所以没有什么需要被复制/复制。并且我们保证编译器会选择任何试图更改参数的错字。
  • 0!=使代码更清晰明了。编写代码的主要目的始终是与其他程序员(包括技能较低的程序员)进行清晰有效的沟通。
  • 虽然不适用于此特定情况...通常,模板化函数避免了多次评估参数的问题。一些#define宏的已知问题。
    例如:#define ABS(X)((((X)<0)?-(X):(X))
          ABS(i ++);

13

所选答案在做什么实际上是错误的。下面的函数将根据该位是否实际使能来返回该位的位置或0。这不是发帖人要的。

#define CHECK_BIT(var,pos) ((var) & (1<<(pos)))

这是海报最初想要的。如果使能该位而不是位置,则下面的函数将返回1或0。

#define CHECK_BIT(var,pos) (((var)>>(pos)) & 1)

1
我花了一些时间才明白您的意思。更确切的说:如果该位置1,则第一个函数将2返回到该位的幂,否则返回0。
lukasl1991 '19

1
这是我在使用它时遇到的确切问题,很高兴bool has_feature = CHECK_BIT(register, 25);知道没有双重否定也可以做到。
Jimmio92

11

根据位域的描述,存在一种用于直接定义和访问域的方法。此条目中的示例为:

struct preferences {
    unsigned int likes_ice_cream : 1;
    unsigned int plays_golf : 1;
    unsigned int watches_tv : 1;
    unsigned int reads_books : 1;
}; 

struct preferences fred;

fred.likes_ice_cream = 1;
fred.plays_golf = 1;
fred.watches_tv = 1;
fred.reads_books = 0;

if (fred.likes_ice_cream == 1)
    /* ... */

另外,这里还有一个警告:

但是,结构中的位成员具有实际缺陷。首先,内存中的位顺序取决于体系结构,并且内存填充规则因编译器而异。此外,许多流行的编译器都会生成用于读取和写入位成员的低效率代码,并且由于大多数机器无法操纵内存中的任意位集,因此存在与位字段相关的潜在严重线程安全问题(尤其是在多处理器系统上),但必须加载并存储整个单词。



5

使用std :: bitset

#include <bitset>
#include <iostream>

int main()
{
    int temp = 0x5E;
    std::bitset<sizeof(int)*CHAR_BITS>   bits(temp);

    // 0 -> bit 1
    // 2 -> bit 3
    std::cout << bits[2] << std::endl;
}

1
这里有几件事值得一提-位[3]将为您提供第4位-从LSB到MSB。简单地说,它将为您提供从右到左计数的第4位。同样,sizeof(int)给出int中的字符数,因此它需要是std :: bitset <sizeof(int)* CHAR_BITS> bits(temp)和bits [sizeof(int)* CHAR_BITS-3]测试从MSB到LSB的第3位计数,这可能是目的。
塑料克里斯

2
是的,但我认为发问者(和来自Google搜索的人)可能没有这种能力,您的回答可能会误导他们。
塑料克里斯

这个答案很糟糕。应该删除它。
亚当·伯瑞

temp不需要将其价值体现为“ big-endian”吗?
jww

4

有,即_bittest内部指令。


3
该链接指示“ Microsoft特定”。仅当不需要代码可移植时才使用它。
mouviciel

该链接指示“ Microsoft Specific”,但这是从Intel C ++编译器接管的一个内部函数,它会导致BT指令,因此您也可以使用内联汇编程序来执行此操作。当然,这并不能使其更加便携。
Dave Van den Eynde,09年

1
它也特定于x86体系结构。所以不,绝对不是便携式的。
jalf

我确信其他架构也有类似的选择。
Dave Van den Eynde,09年

内在函数的重点是,如果存在硬件,它们将利用硬件;如果硬件无法处理,则使用软件替代。

4

我用这个:

#define CHECK_BIT(var,pos) ( (((var) & (pos)) > 0 ) ? (1) : (0) )

其中“ pos”定义为2 ^ n(ig 1,2,4,8,16,32 ...)

返回:如果为true,则返回1;如果为false,则返回0


2
我认为这是C和C ++的唯一正确答案。它是唯一符合“ ...不带移位和屏蔽”要求的设备。您可能应该明确声明要4 = 2^(3-1)用于位置3,因为它是问题的一部分。
jww

3

我试图读取一个32位整数,该整数为PDF中的对象定义了标志,但这对我不起作用

修改定义的原因是:

#define CHECK_BIT(var,pos) ((var & (1 << pos)) == (1 << pos))

操作数&返回一个带有两个都为1的标志的整数,并且没有正确地将其强制转换为布尔值,这可以解决问题


!= 0会做同样的事情。不知道生成的机器指令可能有何不同。
亚当·伯瑞

2

您可以“模拟”移位和屏蔽:if((0x5e /(2 * 2 * 2))%2)...


我们可以通过随机改组并测试列表是否现在已“排序”来对列表进行排序。例如:while(/ * NOT * /!isSorted()){RandomlyShuffle(); }但是我们不……
Ree先生

该解决方案在资源上非常浪费并且不直观。div,muls和mods是三个最昂贵的功能。通过比较测试,ands和shifts是最便宜的-您可能实际上会在不到5个周期内完成一些操作。
jheriko

可能是(不是,因为现代处理器讨厌位和跳转)。OP最初明确要求“没有移位和屏蔽的”解决方案。因此,继续给出更多否定点,以获得匹配但缓慢的答案。我不会因为OP改变主意而删除帖子。
Leonidas

看起来很棘手。我们不要否决这个答案。有时候,探索其他观点是很好的。
越南

2

对于低级别的x86特定解决方案,请使用x86 TEST操作码。

您的编译器应该将_bittest变成这个...


我更喜欢BT而不是TEST,因为BT以更好的方式适合任务。
u_Ltd。

1

为什么不使用像这样简单的东西呢?

uint8_t status = 255;
cout << "binary: ";

for (int i=((sizeof(status)*8)-1); i>-1; i--)
{
  if ((status & (1 << i)))
  {
    cout << "1";
  } 
  else
  {
    cout << "0";
  }
}

输出:二进制: 11111111


如果使用三元数可以轻松完成:std::cout << (((status & (1 << i)) ? '1' : '0');。您应该使用CHAR_BIT的常量<climits>,因为你正在使用的不是硬编码的8位,尽管在这种情况下,你知道结果会是8反正uint8_t
瑞安海宁

0

如果您只想要一种真正的硬编码方式:

 #define IS_BIT3_SET(var) ( ((var) & 0x04) == 0x04 )

请注意,这与硬件相关,并假定该位顺序为7654 3210,并且var为8位。

#include "stdafx.h"
#define IS_BIT3_SET(var) ( ((var) & 0x04) == 0x04 )
int _tmain(int argc, _TCHAR* argv[])
{
    int temp =0x5E;
    printf(" %d \n", IS_BIT3_SET(temp));
    temp = 0x00;
    printf(" %d \n", IS_BIT3_SET(temp));
    temp = 0x04;
    printf(" %d \n", IS_BIT3_SET(temp));
    temp = 0xfb;
    printf(" %d \n", IS_BIT3_SET(temp));
    scanf("waitng %d",&temp);

    return 0;
}

结果是:

1 0 1 0


1
&操作是对内部表示形式上的值完成的。
Remo.D

嗨Remo.D-不确定我是否理解您的评论?我提供了一些可以正常工作的“ c”代码。
simon,2009年

他的观点是,它与硬件无关-IS_BIT3_SET将始终测试第4个最低有效位
Eclipse

0

尽管现在回答还为时已晚,但是有一种简单的方法可以简单地使用POWER和MODULUS数学运算符来查找是否设置了第N位。

假设我们想知道'temp'是否设置了Nth位。如果设置了位,则以下布尔表达式将为true,否则为0。

  • (模数2 ^ N + 1> = 2 ^ N)

考虑以下示例:

  • int temp = 0x5E; //在二进制0b1011110中// BIT 0为LSB

如果我想知道是否设置了第三位,我得到

  • (94模16)= 14> 2 ^ 3

因此,表达式返回true,表示已设置第3位。


0

一种方法是在以下情况下进行检查:

if ( (mask >> bit ) & 1)

一个解释程序将是:

#include <stdio.h>

unsigned int bitCheck(unsigned int mask, int pin);

int main(void){
   unsigned int mask = 6;  // 6 = 0110
   int pin0 = 0;
   int pin1 = 1;
   int pin2 = 2;
   int pin3 = 3;
   unsigned int bit0= bitCheck( mask, pin0);
   unsigned int bit1= bitCheck( mask, pin1);
   unsigned int bit2= bitCheck( mask, pin2);
   unsigned int bit3= bitCheck( mask, pin3);

   printf("Mask = %d ==>>  0110\n", mask);

   if ( bit0 == 1 ){
      printf("Pin %d is Set\n", pin0);
   }else{
      printf("Pin %d is not Set\n", pin0);
   }

    if ( bit1 == 1 ){
      printf("Pin %d is Set\n", pin1);
   }else{
      printf("Pin %d is not Set\n", pin1);
   }

   if ( bit2 == 1 ){
      printf("Pin %d is Set\n", pin2);
   }else{
      printf("Pin %d is not Set\n", pin2);
   }

   if ( bit3 == 1 ){
      printf("Pin %d is Set\n", pin3);
   }else{
      printf("Pin %d is not Set\n", pin3);
   }
}

unsigned int bitCheck(unsigned int mask, int bit){
   if ( (mask >> bit ) & 1){
      return 1;
   }else{
      return 0;
   }
}

输出:

Mask = 6 ==>>  0110
Pin 0 is not Set
Pin 1 is Set
Pin 2 is Set
Pin 3 is not Set

0
#define CHECK_BIT(var,pos) ((var>>pos) & 1)

pos-位位置从0开始。

返回0或1。


-1

我做这个:

LATGbits.LATG0 =(((m&0x8)> 0); //检查m的第2位是否为1


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.