26

我试图在 64 位数字中找到两个 1 的位置。在这种情况下,它们位于第 0 位和第 63 位。这里的代码返回 0 和 32,只对了一半。为什么这不起作用?

#include<stdio.h>
void main()
{
unsigned long long number=576460752303423489;
int i;
for (i=0; i<64; i++)
    {
    if ((number & (1 << i))==1)
        {
        printf("%d  ",i);

        }   
    }
}
4

6 回答 6

24

线上有两个bug

if ((number & (1 << i))==1)

应该读

if (number & (1ull << i))

更改11ull意味着左移是在类型unsigned long long而不是的值上完成的int,因此位掩码实际上可以到达位置 32 到 63。删除与 1 的比较是因为number & mask(其中mask只有一个位集)的结果是mask或者0,mask只有当 i 为 0 时才等于 1。

但是,当我进行更改时,我的输出是0 59,这仍然不是您所期望的。剩下的问题是 576460752303423489(十进制)= 0800 0000 0000 0001(十六进制)。 0 59是该数字的正确输出。您想要的数字是 9223372036854775809(十进制)= 8000 0000 0000 0001(十六进制)。

顺便说一句,main需要 return int, not void,并且需要显式return 0;作为其最后一个操作(除非您使用返回代码做一些更复杂的事情)。是的,C99 可以让你省略它。无论如何都要这样做。

于 2013-09-18T15:30:01.623 回答
6

因为是您正在编译和运行的平台上(1 << i)的 32 位值。int然后将符号扩展为 64 位,以便&使用该number值进行操作,从而导致第 31 位被复制到第 32 位到第 63 位。

此外,您正在将结果与&1 进行比较,这是不正确的。如果设置了该位,它将不会为 0,但不会为 1。

将 32 位 int 移位 32 位是未定义的。

另外,您输入的号码不正确。位设置在位置 0 和 59(如果您更喜欢从 1 开始计数,则为 1 和 60)。

解决方法是使用 (1ull << i),或者以其他方式将原始值和&它右移 1(而不是左移 1)。当然,如果您将 1 与原始值进行左移&,则结果不会为 1(位 0 除外),因此您需要比较!= 0而不是== 1.

于 2013-09-18T15:27:30.940 回答
4
#include<stdio.h>
int main()
{
    unsigned long long number = 576460752303423489;
    int i;
    for (i=0; i<64; i++)
    {
        if ((number & (1ULL << i)))   //here
        {
            printf("%d  ",i);    
        }   
    }
}

首先是用来1ULL表示unsigned long long常数。其次是在if声明中,您的意思是不与 比较1,这仅适用于最右边的位。

输出:0 59

这是正确的,因为576460752303423489等于0x800000000000001

于 2013-09-18T15:31:50.610 回答
1

通过采用将>>运算符应用于变量而不是文字的方法,可以首先避免该问题:

if ((variable >> other_variable) & 1)
   ...
于 2013-09-18T19:11:16.070 回答
0

我知道这个问题有一些时间和多个正确答案,而我的应该是评论,但对它来说有点太长了。我建议您将位检查逻辑封装在宏中,不要直接使用 64 数字,而是计算它。在这里查看相当全面的位操作技巧来源。

#include<stdio.h>
#include<limits.h>

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

int main(void)
{
    unsigned long long number=576460752303423489;
    int pos=sizeof(unsigned long long)*CHAR_BIT-1;    
    while((pos--)>=0) {
        if(CHECK_BIT(number,pos))
            printf("%d ",pos);
    }
    return(0);
}
于 2013-09-18T18:57:03.677 回答
0

与其求助于位操作,不如使用编译器工具以最有效的方式执行位分析任务(在许多情况下仅使用一条 CPU 指令)。

例如,gcc 和 clang 提供了这些方便的例程:

__builtin_popcountll() - number of bits set in the 64b value
__builtin_clzll() - number of leading zeroes in the 64b value
__builtin_ctzll() - number of trailing zeroes in the 64b value
__builtin_ffsll() - bit index of least significant set bit in the 64b value

其他编译器也有类似的机制。

于 2013-09-19T04:12:37.553 回答