Wie kann man ein Bit setzen, löschen und umschalten?
Antworten
Zu viele Anzeigen?Der Bitfeld-Ansatz hat im eingebetteten Bereich weitere Vorteile. Sie können eine Struktur definieren, die direkt auf die Bits in einem bestimmten Hardware-Register abgebildet wird.
struct HwRegister {
unsigned int errorFlag:1; // one-bit flag field
unsigned int Mode:3; // three-bit mode field
unsigned int StatusCode:4; // four-bit status code
};
struct HwRegister CR3342_AReg;
Sie müssen die Reihenfolge der Bitpackung beachten - ich glaube, es ist MSB first, aber das kann von der Implementierung abhängen. Überprüfen Sie auch, wie Ihr Compiler Felder behandelt, die Byte-Grenzen überschreiten.
Sie können dann die einzelnen Werte wie bisher lesen, schreiben und testen.
Prüfen eines Bits an einer beliebigen Stelle in einer Variablen beliebigen Typs:
#define bit_test(x, y) ( ( ((const char*)&(x))[(y)>>3] & 0x80 >> ((y)&0x07)) >> (7-((y)&0x07) ) )
Beispielhafte Verwendung:
int main(void)
{
unsigned char arr[8] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF };
for (int ix = 0; ix < 64; ++ix)
printf("bit %d is %d\n", ix, bit_test(arr, ix));
return 0;
}
Anmerkungen: Es ist so konzipiert, dass es schnell (angesichts seiner Flexibilität) und nicht verzweigt ist. Es führt zu effizientem SPARC-Maschinencode, wenn es mit Sun Studio 8 kompiliert wird; ich habe es auch mit MSVC++ 2008 auf amd64 getestet. Es ist möglich, ähnliche Makros für das Setzen und Löschen von Bits zu erstellen. Der Hauptunterschied dieser Lösung im Vergleich zu vielen anderen hier ist, dass sie für jede Stelle in so ziemlich jedem Variablentyp funktioniert.
Dieses Programm ändert ein beliebiges Datenbit von 0 auf 1 oder 1 auf 0:
{
unsigned int data = 0x000000F0;
int bitpos = 4;
int bitvalue = 1;
unsigned int bit = data;
bit = (bit>>bitpos)&0x00000001;
int invbitvalue = 0x00000001&(~bitvalue);
printf("%x\n",bit);
if (bitvalue == 0)
{
if (bit == 0)
printf("%x\n", data);
else
{
data = (data^(invbitvalue<<bitpos));
printf("%x\n", data);
}
}
else
{
if (bit == 1)
printf("elseif %x\n", data);
else
{
data = (data|(bitvalue<<bitpos));
printf("else %x\n", data);
}
}
}
Wenn Sie viel an den Bits herumschrauben, sollten Sie Masken verwenden, um das Ganze zu beschleunigen. Die folgenden Funktionen sind sehr schnell und dennoch flexibel (sie erlauben Bit-Twiddling in Bitmaps jeder Größe).
const unsigned char TQuickByteMask[8] =
{
0x01, 0x02, 0x04, 0x08,
0x10, 0x20, 0x40, 0x80,
};
/** Set bit in any sized bit mask.
*
* @return none
*
* @param bit - Bit number.
* @param bitmap - Pointer to bitmap.
*/
void TSetBit( short bit, unsigned char *bitmap)
{
short n, x;
x = bit / 8; // Index to byte.
n = bit % 8; // Specific bit in byte.
bitmap[x] |= TQuickByteMask[n]; // Set bit.
}
/** Reset bit in any sized mask.
*
* @return None
*
* @param bit - Bit number.
* @param bitmap - Pointer to bitmap.
*/
void TResetBit( short bit, unsigned char *bitmap)
{
short n, x;
x = bit / 8; // Index to byte.
n = bit % 8; // Specific bit in byte.
bitmap[x] &= (~TQuickByteMask[n]); // Reset bit.
}
/** Toggle bit in any sized bit mask.
*
* @return none
*
* @param bit - Bit number.
* @param bitmap - Pointer to bitmap.
*/
void TToggleBit( short bit, unsigned char *bitmap)
{
short n, x;
x = bit / 8; // Index to byte.
n = bit % 8; // Specific bit in byte.
bitmap[x] ^= TQuickByteMask[n]; // Toggle bit.
}
/** Checks specified bit.
*
* @return 1 if bit set else 0.
*
* @param bit - Bit number.
* @param bitmap - Pointer to bitmap.
*/
short TIsBitSet( short bit, const unsigned char *bitmap)
{
short n, x;
x = bit / 8; // Index to byte.
n = bit % 8; // Specific bit in byte.
// Test bit (logigal AND).
if (bitmap[x] & TQuickByteMask[n])
return 1;
return 0;
}
/** Checks specified bit.
*
* @return 1 if bit reset else 0.
*
* @param bit - Bit number.
* @param bitmap - Pointer to bitmap.
*/
short TIsBitReset( short bit, const unsigned char *bitmap)
{
return TIsBitSet(bit, bitmap) ^ 1;
}
/** Count number of bits set in a bitmap.
*
* @return Number of bits set.
*
* @param bitmap - Pointer to bitmap.
* @param size - Bitmap size (in bits).
*
* @note Not very efficient in terms of execution speed. If you are doing
* some computationally intense stuff you may need a more complex
* implementation which would be faster (especially for big bitmaps).
* See (http://graphics.stanford.edu/~seander/bithacks.html).
*/
int TCountBits( const unsigned char *bitmap, int size)
{
int i, count = 0;
for (i=0; i<size; i++)
if (TIsBitSet(i, bitmap))
count++;
return count;
}
Hinweis: Um Bit 'n' in einer 16-Bit-Ganzzahl zu setzen, gehen Sie wie folgt vor
TSetBit( n, &my_int);
Es liegt an Ihnen sicherzustellen, dass die Bitnummer innerhalb des Bereichs der übergebenen Bitmap liegt. Beachten Sie, dass bei "Little-Endian"-Prozessoren Bytes, Wörter, D-Wörter, Q-Wörter usw. im Speicher korrekt aufeinander abgebildet werden (Hauptgrund dafür, dass "Little-Endian"-Prozessoren "besser" sind als "Big-Endian"-Prozessoren, ach, ich spüre, dass ein Flame-War im Anmarsch ist...).
90 Stimmen
Lesen Sie dies: graphics.stanford.edu/~seander/bithacks.html und, wenn du das gemeistert hast, lies das hier: realtimecollisiondetection.net/blog/?p=78
22 Stimmen
Das könnte Sie auch interessieren Der Gebissverdreher , Bit Twiddling Hacks und Die Aggregat-Magie-Algorithmen .
0 Stimmen
Das wirft die Frage auf, was die kanonische Frage für mehrere Bits ist.
2 Stimmen
Verwandt: Was sind bitweise Verschiebungsoperatoren (Bit-Shift) und wie funktionieren sie?
2 Stimmen
Einige Kandidaten: Ersetzen von Bits in einem Bitfeld ohne Auswirkungen auf andere Bits mit C (2011), und Wie kann man in C nur bestimmte Bits eines Bytes setzen, ohne den Rest zu beeinflussen? (2010)