[英]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
的指針,因此其算法不正確。 當打算計算buf
加length
long
對象時,它將計算buf
加length
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
,這甚至更糟-如果您buf
在buf
之外進行讀取,那么現在代碼正在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.