2012-01-19 15 views
17

Chcę prostej funkcji C, która zwróci wartość true, jeśli n-ty bit w bajcie jest ustawiony na 1. W przeciwnym razie zwróci false.funkcja sprawdzająca, czy n-ty bit jest ustawiony w bajcie

Jest to funkcja krytyczna pod względem czasu wykonania, więc mam na myśli najbardziej optymalny sposób na to.

+1

Duplikat, http://stackoverflow.com/questions/523724/cc-check-if-one-bit-is -set-in-ie-int-variable – blueshift

+4

To nie jest dupe, szczególnie pytano o metody ** non-bitshift **. – paxdiablo

Odpowiedz

32

Poniższa funkcja może zrobić to, czego potrzebujesz:

int isNthBitSet (unsigned char c, int n) { 
    static unsigned char mask[] = {128, 64, 32, 16, 8, 4, 2, 1}; 
    return ((c & mask[n]) != 0); 
} 

Zakłada 8-bitowych bajtów (nie podano w C) i nieco zerowego jest najwyższy order jeden. Jeśli te założenia są niepoprawne, po prostu sprowadza się do rozszerzenia i/lub ponownego uporządkowania tablicy mask.

Nie należy sprawdzać błędów, ponieważ jako najważniejszą uwagę podano prędkość. Czy nie przekazać nieprawidłowy n, które będzie niezdefiniowane zachowanie.

Na insane poziom optymalizacji -O3, gcc daje nam:

isNthBitSet: pushl %ebp 
       movl %esp, %ebp 
       movl 12(%ebp), %eax 
       movzbl 8(%ebp), %edx 
       popl %ebp 
       testb %dl, mask(%eax) 
       setne %al 
       movzbl %al, %eax 
       ret 
mask:   .byte -128, 64, 32, 16, 8, 4, 2, 1 

który jest dość mały i wydajny. A jeśli uczynisz to statycznym i zaproponujesz inlining lub wymusisz inline jako definicję makra, możesz nawet ominąć koszt wywołania funkcji.

Po prostu upewnij się, że porównujesz wszystkie dostępne rozwiązania, w tym jeden: (a). Najlepsza mantra w optymalizacji to "Zmierz się, nie zgaduj!"

Jeśli chcesz wiedzieć, jak działają operatory bitowe, zobacz here. Uproszczona wersja tylko AND jest poniżej.

Operacja I & ustawi bit w celu tylko wtedy, gdy oba bity zostaną ustawione w tych źródłach. Odpowiednia tabela:

AND | 0 1 
----+---- 
0 | 0 0 
1 | 0 1 

Dla danej wartości char używamy maski single-Bit, by sprawdzić, czy bit jest ustawiony. Powiedzmy, że masz wartość 13 i chcesz sprawdzić, czy ustawiony jest trzeci od najmniej znaczącego bitu.

Decimal Binary 
    13  0000 1101 
    4  0000 0100 (the bitmask for the third-from-least bit). 
     ========= 
     0000 0100 (the result of the AND operation). 

Można zobaczyć, że wszystkie bity zerowe w masce powodują, że równoważne bity wynikowe wynoszą zero. Pojedynczy bit w masce zasadniczo pozwoli bitu ekwiwalentnemu w przepływie wartości przejść do wyniku. Wynik jest wtedy zerowy, jeśli bit, który sprawdzamy, był równy zeru lub niezerowy, jeśli był jeden.

To stąd pochodzi wyrażenie w instrukcji return. Wartości w tabeli przeglądowej mask są wszystkie maski single-bitowe:

Decimal Binary 
    128 1000 0000 
    64 0100 0000 
    32 0010 0000 
    16 0001 0000 
    8 0000 1000 
    4 0000 0100 
    2 0000 0010 
    1 0000 0001 

(a) wiem jak dobry jestem, ale nie :-)

+2

Tablica wyników, tak! Ale spodziewałbym się, że bit 0 będzie najmniej znaczącym bitem w bajcie, a więc odwróciłby kolejność wpisów 'mask []' intialized. – hardmath

+0

Nie zawsze, @hardmath, wiele standardów komunikacyjnych wypełnia ich oktety z "lewej". Podobnie jak Ty wolę myśleć o b0 jako najmniej znaczącym. – paxdiablo

+0

-1, szczegółowe i podatne na błędy, aby pisać, dowiedzieć się o zmianie bitów. – blueshift

20

Wystarczy sprawdzić wartość (1 << bit) & byte. Jeśli jest niezerowe, bit jest ustawiony.

3
bool isSet(unsigned char b, unsigned char n) { return b & (1 << n); } 
+0

Rozumiem 'unsigned char' dla wartości bajtów, ale' n'? Wydaje się to dziwne. – Rob

+0

well n nie może być większy niż bajt ... nie ma to większego znaczenia –

+0

Ponieważ 'unsigned char' nie ogranicza n tylko do poprawnych wartości, argumentowałbym, że jest to [mały]" zapach kodu "w odniesieniu do do czytelności. Oczywiście, to jest dyskusyjne i zgodzę się, że to nie ma znaczenia. – Rob

8

Niech numer będzie num. Następnie:

return ((1 << n) & num); 
+0

Czy możesz wyjaśnić ten kod? – vidyasagarr7

2
#include<stdio.h> 
int main() 
{ 
    unsigned int n,a; 
    printf("enter value for n\n"); 
    scanf("%u",&n); 
    pintf("enter value for a:\n"); 
    scanf("%u",&a); 
    a= a|(((~((unsigned)0))>>(sizeof(int)*8-1))<<n); 
    printf("%u\n",a); 
} 
2

Innym rozwiązaniem byłoby

bool isNthBitSet (unsigned char c, int n) { 
     return (1 & (c >> n)); 
    } 
0
#include<stdio.h> 

int main() 
{ 
     int data,bit; 
     printf("enter data:"); 
     scanf("%d",&data); 
     printf("enter bit position to test:"); 
     scanf("%d",&bit); 
     data&(1<<bit)?printf("bit is set\n"):printf("bit is clear\n"); 

    return 0; 
} 
+2

Ta odpowiedź kodu wymaga pewnych wyjaśnień, aby wartość dodana była bardziej oczywista, w porównaniu do innych, starszych, przejętych i w większości lepiej wyjaśnionych odpowiedzi (nie oznacza to, że wszystkie inne odpowiedzi są lepiej wyjaśnione ...). – Yunnosch

Powiązane problemy