首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >计算数组中值为1的位数 - 了解其背后的代码(C)?

计算数组中值为1的位数 - 了解其背后的代码(C)?
EN

Stack Overflow用户
提问于 2018-06-26 05:49:33
回答 1查看 0关注 0票数 0

以下代码计算数组'buf'中值为'1'的位数:

代码语言:javascript
复制
long bit_count(long *arr, int size)
{
    int w,b;
    unsigned long word=0;
    long n = 0;

    for(w = 0; w<size ; w++){
        word = arr[w];
        while(word != 0){
            n += word & 1;
            word >>= 1;
        }
    }
    return n;
}

int main() {

     char buf[] = {"There is always one more!"};         //(1)
     int length = strlen(buf)>>3;                        //(2)
     long *a = (long*) (buf + length);                   //(3)
     //char * b = (char *)a; // this is a comment.       //(4)
     int len = strlen((char*)a);                         //(5)
     long total_count = bit_count((long*) buf, length);  //(6)
     *a = (*a) & (((long)1<<(len*8))-1);                 //(7)
     char *c = (char*)a;                                 //(8)
     total_count += bit_count(a,1);                      //(9)
     printf("bits number %ld\n",total_count);            //(10)

    return 0;
}

这是我对代码的理解:(如果我错了,请纠正我,我想在最深层次上理解它)

在第(2)行中,它们计算出buf中25个字母的字符数,相当于25个字节。导致char的大小是1个字节。然后通过将该3位向右移动它们将其除以8,8定义8字节= 1长类型。所以这个buf数组包含多少“long”。

第(3)行 - 'a'指向一个值,该值包含将行的其余部分转换为(long *)- 在第(4)行中,我看到b *值将是“!” 这正好是数组中1个字节的剩余部分。但我真的不明白,(long *)如果我检查,铸造到我得到的价值是不同的

代码语言:javascript
复制
long check = (long) (buf + length);

那么当我做什么时会发生什么 - {(long*)buf} 是我的第一个问题。

在第(6)行中,我对数组第一部分的位进行计数(按长整数),并在行(9)中对余数中的位进行计数。

我不明白的是 - 第(7)行发生了什么?

EN

回答 1

Stack Overflow用户

发布于 2018-06-26 15:45:22

代码语言:javascript
复制
(2)  int length = strlen(buf)>>3;

这条线计算出long适合字符串的整个对象数量,假设它long是八个字节(/ sizeof(long)应该用来代替>>3),并且它int足够大以容纳数字(size_t应该用来代替int)。

代码语言:javascript
复制
(3)  long *a = (long*) (buf + length);

这似乎打算设置a为指向不足以包含另一个long对象的字符串末尾的片段。但是,因为length是一些long对象并buf充当指针char,所以其算术运算不正确。它计算buf加上length char对象时,它打算计算buflength long对象。它应该使用(long *) buf + length。此外,它假设char *任意对齐可以明智地转换为a long *,这是C标准所不能保证的。

代码语言:javascript
复制
(5)  int len = strlen((char*)a);

这将计算片段中的字节数。这是一种浪费,因为代码先前计算了字符串的长度。它可以节省那么长的时间,并将商数和余数取模为大小long而不是strlen再次调用。

代码语言:javascript
复制
(6)  long total_count = bit_count((long*) buf, length);

这将计算在缓冲区的主要部分中设置的位数,也就是被视为一些整数long对象的部分。与之前的转换一样,它假设a char *可以转换为a long *,并且进一步调用的例程使用该指针long从未定义为数组的对象中读取对象long,从而违反了C别名规则。

代码语言:javascript
复制
(7)  *a = (*a) & (((long)1<<(len*8))-1);

回想一下,a指向字符串中的一些尾部字节数。(long)1<<(len*8)假设字节是8位(CHAR_BIT应该用来代替8),移动一点到略高于该字节数。(例如,如果有两个字节,则会创建值10000 16)。然后减去1将为字节创建一个位掩码(示例中为FFFF 16)。然后*a尝试long从字符串的末尾读取一个字符串,之后应用掩码&将读取的值减少为字符串中的字节。这不仅违反了C的别名规则,而且还在内存之外读取buf,这具有未定义的行为。最后,该语句将更新的值写入*a,这更糟糕 - 如果你不在阅读范围之外buf,现在代码在外面写buf,导致某处不明的腐败。

代码语言:javascript
复制
(8)  char *c = (char*)a;

这条线是无用的,因为c从来没有使用过。

代码语言:javascript
复制
(9)  total_count += bit_count(a,1);

这将计算long在(7)中更新的位数。

bit_count例程中,我们发现代码正在逐个计数位。这是荒谬的。如果使用特定的C实现允许使用未对齐的地址进行别名,则违反关于别名的C规则可能对于处理整个long对象而不是单个char对象有一定的性能好处。但是这个代码只是逐位处理; 它不会从处理器上的某些位计数(也称为总体计数)指令中获得任何优势。

此外,bit_count例行程序认识到它应该unsigned long用于位计数,因为它定义wordunsigned long。但它没有认识到它应该在unsigned long整个过程中使用,因为它long可能有陷阱表示会导致代码失败。

它也定义b而不用它。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/-100005523

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档