有人可以向我解釋這個函數嗎?如何在C中創建最小有效位設置爲1的掩碼
設置爲1
實施例的至少顯著n位的掩模:
N = 6 - >值爲0x2F,N = 17 - > 0x1FFFF //我沒有得到這些在所有,特別是如何n = 6 - > 0x2F
此外,什麼是面具?
有人可以向我解釋這個函數嗎?如何在C中創建最小有效位設置爲1的掩碼
設置爲1
實施例的至少顯著n位的掩模:
N = 6 - >值爲0x2F,N = 17 - > 0x1FFFF //我沒有得到這些在所有,特別是如何n = 6 - > 0x2F
此外,什麼是面具?
通常的做法是取一個1
,並將其左移n
位。這會給你類似於:00100000
。然後從中減去一個,這將清除已設置的位,並設置所有不重要的位,因此在這種情況下,我們會得到:00011111
。
掩碼通常用於按位操作,特別是and
。您可以使用上面的掩碼自行獲取5個最不重要的位,與其他可能存在的其他位相隔離。在處理硬件時,這種情況尤其常見,硬件通常會有一個硬件寄存器,其中的硬件寄存器中的位代表許多完全獨立的,不相關的數量和/或標誌。
請記住,去'1 << w-1',其中'w'是寬度數據類型,除了一個位外,都是UB。 – chris
沒錯。歸咎於英特爾,但它達到了標準。 – wildplasser
有關以這種方法從UB中統一恢復的方法,請參閱下面的答案。 – user13972
我相信你的第一個例子應該是0x3f
。
0x3f
爲這是在二進制111111
數63
十六進制表示,以使得最後的6位(最低顯著6個比特)被設置爲1
。
以下小C程序將計算出正確的掩模:
#include <stdarg.h>
#include <stdio.h>
int mask_for_n_bits(int n)
{
int mask = 0;
for (int i = 0; i < n; ++i)
mask |= 1 << i;
return mask;
}
int main (int argc, char const *argv[])
{
printf("6: 0x%x\n17: 0x%x\n", mask_for_n_bits(6), mask_for_n_bits(17));
return 0;
}
0x2F
是二進制0010 1111
- 這應該是0x3f
,這在二進制0011 1111
並具有設定的6個最低-顯著位。
類似地,0x1FFFF
是二進制的0001 1111 1111 1111 1111
,其具有設置的17個最低有效位。
「掩模」是旨在與另一值進行組合使用按位操作者像&
,|
或^
個別地設定,取消設置,在該另一值翻轉或離開不變的位的值。
例如,如果您使用的&
運營商一定的價值n
結合面具0x2F
,結果將在所有零,但至少6位顯著,和那些6位將從值n
複製不變。
對於&
掩碼,掩碼中的二進制0
表示「無條件地將結果位設置爲0」,而1
表示「將結果位設置爲輸入值位」。對於|
掩模,在掩模中的0
設置結果位到輸入比特和1
無條件地將結果位1
,以及用於^
掩模,一個0
設置結果位到輸入比特和1
設置結果位到輸入位的補碼。
Ops。更新後得到錯誤的編輯,但我做了回滾。抱歉! – jweyrich
掩碼是一個整數值的通用術語,它與另一個整數值進行按位,與或與異或等操作。
例如,如果要提取int變量的8個最低有效位數,請執行variable & 0xFF
。 0xFF是一個掩碼。
同樣,如果你想設置位0和8,你做variable | 0x101
,其中0x101是一個掩碼。
或者如果你想反轉相同的位,你可以做variable^0x101
,其中0x101是一個掩碼。
要爲您的案例生成一個掩碼,您應該利用簡單的數學事實,如果您將1添加到掩碼(掩碼將其所有最低有效位設置爲1,其餘爲0),則會得到一個值是2的冪。因此,如果你生成2的最接近的冪,那麼你可以從它減去1來獲得掩碼。
的2正極權力在C.
與左移<<
操作者容易產生
因此,1 << n
產量2 Ñ。在二進制中它是10 ... 0與n
0s。
(1 << n) - 1
會產生設置爲1
現在n
最低位的面具,你需要提防左移溢出。在C(和C++)中,不能合法地將變量左移多個位的位置,因此如果整數是32位,則1<<32
結果爲undefined behavior
。也應該避免帶符號的整數溢出,所以你應該使用無符號的值,例如1u << 31
。
對於正確性和性能而言,由於在現代x86處理器(特別是BLSMSK)中出現BMI指令,因此在2012年要求回答此問題的最佳方法已經發生了變化。
下面是解決這個問題的好方法,同時保持與舊處理器的向後兼容性。
該方法是正確的,而當前的最佳答案會在邊緣情況下產生未定義的行爲。
當允許使用BMI指令進行優化時,Clang和GCC會將gen_mask()簡化爲兩個操作。隨着支持硬件,一定要添加的編譯器標誌爲BMI說明: -mbmi -mbmi2
#include <inttypes.h>
#include <stdio.h>
uint64_t gen_mask(const uint_fast8_t msb) {
const uint64_t src = (uint64_t)1 << msb;
return (src - 1)^src;
}
int main() {
uint_fast8_t msb;
for (msb = 0; msb < 64; ++msb) {
printf("%016" PRIx64 "\n", gen_mask(msb));
}
return 0;
}
你有一個錯誤的AFAICT錯誤。 –
對不起,這是一個誤解:我會使用寬度作爲參數(如OP提到的N),但由於您使用MSB的索引,它實際上是一致的。 –
在這種情況下,consting會做什麼? –
*也什麼是面具* [如何維基百科?](http://en.wikipedia.org/wiki/Mask_? (計算)) – chris
0x2F是錯誤的,它應該是0x3f – wich
@chris wiki太混亂了...... – sebi