簡體   English   中英

計算數組中值1的位數-了解其背后的代碼(C)

[英]Counting the number of bits of value 1 in an array - Understanding the code behind it (C)

以下代碼計算數組“ buf”中值“ 1”的位數:

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個long類型。 那么這個buf數組包含多少個“ long”。

第(3)行-'a'指向包含buf其余部分到(long *) -在第(4)行中,我看到b *值為“!” 恰好是數組中1個字節的剩余部分。 但是我不太理解強制轉換為(long *)我得到的值是否不同,如果我檢查

long check = (long) (buf + length);

所以當我這樣做時,究竟發生了什么- {(long*)buf}是我的第一個問題。

在第(6)行中,我對數組的第一部分中的位進行計數(按長整數),在第(9)行中,我對其余部分中的位進行計數。

我不明白的是-在第(7)行中會發生什么?

該代碼沒有什么棘手的問題,但不是很好。 實際上,這很糟糕,不是因為樣式,而是因為它破壞了內存。

(2)  int length = strlen(buf)>>3;

該行計算適合字符串的long對象的總數,假設long為8個字節(應使用/ sizeof(long)而不是>>3 ),並且int足夠大以容納數字( size_t應為用於代替int )。

(3)  long *a = (long*) (buf + length);

這似乎打算將a設置為指向字符串末尾的片段,該片段長度不足以包含另一個long對象。 但是,由於length是多個long對象,而buf充當char的指針,因此其算法不正確。 當打算計算buflength long對象時,它將計算buflength char對象。 應該使用(long *) buf + length 同樣,它假定具有任意對齊方式的char *可以合理地轉換為long * ,這不是C標准所保證的。

(5)  int len = strlen((char*)a);

這將計算片段中的字節數。 這是浪費的,因為該代碼先前已計算出字符串的長度。 可以節省該長度,並采用long大小的商和余數取模,而不用再次調用strlen

(6)  long total_count = bit_count((long*) buf, length);

這將計算設置在緩沖區主要部分中的位數,即設置為某些long對象總數的部分。 與較早的轉換一樣,它假定可以將char *轉換為long * ,並且進一步,它調用的例程使用該指針從未定義為long數組的對象中讀取long對象,從而違反了C別名。規則。

(7)  *a = (*a) & (((long)1<<(len*8))-1);

回想一下, a指向字符串中一定數量的尾隨字節。 假設字節為八位,則(long)1<<(len*8)將移至該字節數的正上方(應使用CHAR_BIT而不是8 )。 (例如,如果有兩個字節,這將創建值10000 16。 )然后減去一個將為字節創建一個位掩碼(示例中為FFFF 16 )。 然后*a嘗試從字符串末尾讀取long ,然后使用&加上掩碼,將讀取的值減小為僅字符串中的字節。 這不僅再次違反了C的別名規則,而且還在具有未定義行為的buf內存之外進行讀取。 最后,該語句將更新后的值寫入*a ,這甚至更糟-如果您bufbuf之外進行讀取,那么現在代碼正在buf之外進行寫入,從而導致未知位置的損壞。

(8)  char *c = (char*)a;

這行是無用的,因為從不使用c

(9)  total_count += bit_count(a,1);

這將計算在(7)中更新的long中設置的位數。

bit_count例程中,我們發現代碼正在逐位計數位。 這是荒謬的。 如果使用的特定C實現允許使用未對齊地址的別名,則違反有關別名的C規則可能會有意義,從而獲得了處理整個long對象而不是單個char對象的一些性能優勢。 但是這段代碼只是進行一點一點的處理。 它沒有從處理器上的某些位計數(也稱為填充計數)指令中獲得任何好處。

此外,由於bit_count例程將word定義為unsigned long ,因此它bit_count unsigned long用於位數。 但是它無法識別它應該一直使用unsigned long ,因為long可能具有陷阱表示,這將導致代碼失敗。

它也定義b而不用它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM