2017-10-02 9 views
1

Ich arbeite mit C und ich versuche herauszufinden, wie Sie eine Reihe von Bits in einer 32-Bit-Ganzzahl ohne Vorzeichen ändern.Manuelles Ändern einer Gruppe von Bytes in einem unsigned int

Zum Beispiel, wenn ich

int a = 17212403u; 

In binären haben, das wird 1000001101010001111110011. Wenn ich nun diese Bits, die im Little-Endian-Format angeordnet sind, so beschriftete, dass das Bit ganz rechts die Einsen darstellt, dann sind die Zweien rechts, usw., wie kann ich eine Gruppe von Bits manuell ändern?

Angenommen, ich wollte die Bits so ändern, dass das 11. bis 15. Bit den Dezimalwert 17 hat. Wie wäre das möglich?

Ich dachte an diesen Bereich bekommen, indem sie als solche zu tun:

unsigned int range = (a << (sizeof(a) * 8) - 14) >> (28) 

Aber ich bin nicht sicher, wo von nun an weitergehen.

+1

'int a = 17212403u;' weist einer _signed_ Variablen einen Wert _unsigned_ zu. Sicherlich ist es viel weniger problematisch, Verschiebungen mit vorzeichenlosen Variablen und Konstanten zu machen. Recommend 'unsigned a = 17212403u;' – chux

+1

17 ist 10001B. Bit 11-15 ist auch 5 Bit, also wird es passen. Zuerst erzwingen Sie diese Bits durch AND-Verknüpfung mit einer Maske von NOT (11111B << 11). Dann verschiebe die 17 bis 11 Stellen, und ODER es ein. –

+4

Little-und Big-Endian gelten nicht für Bit "bestellen". Da Bits nicht einzeln adressierbar sind, gibt es kein Konzept für eine niedrigere Adresse, auf die man sich berufen kann. Aber es ist erwähnenswert, dass Little-Endian * Byte * Reihenfolge bedeutet, dass das "am weitesten links" Byte (das mit der niedrigsten Adresse) ist das Ende niedriger Ordnung, das ist das Gegenteil von dem, was Sie denken, "Little-Endian" bedeutet . – rici

Antwort

2

Sie müssen (1) zuerst die Bits 11.15 löschen und (2) dann die Bits entsprechend dem Wert setzen, den Sie einstellen möchten. Um (1) zu erreichen, erstellen Sie eine "Maske", bei der alle Bits auf 1 gesetzt sind, mit Ausnahme der zu löschenden Bits. Verwenden Sie dann a & bitMask, um die Bits auf 0 zu setzen. Verwenden Sie dann | myValue, um die Bits auf den gewünschten Wert zu setzen. den Bit-Shift-Operator << Verwenden Sie die Maske und den Wert an den richtigen Positionen zu platzieren:

int main(int argc, char** argv) { 

    // Let's assume a range of 5 bits 
    unsigned int bitRange = 0x1Fu; // is ...00000000011111 

    // Let's assume to position the range from bit 11 onwards (i.e. move 10 left): 
    bitRange = bitRange << 10;    // something like 000000111110000000000 
    unsigned int bitMask = ~bitRange;  // something like 111111000001111111111 
    unsigned int valueToSet = (17u << 10); // corresponds to 000000101110000000000 

    unsigned int a = (17212403u & bitMask) | valueToSet; 

    return 0; 
} 

Dies ist die lange Version ist zu erklären, was los ist. Kurz gesagt, Sie könnten auch schreiben:

unsigned int a = (17212403u & ~(0x1Fu << 10)) | (17u << 10) 
2

Das 11. bis 15. Bit ist 5 Bits, vorausgesetzt, Sie meinen, dass das 15. Bit enthalten ist. 5 Bits ist der Hex-Wert: 0x1f

Dann verschieben Sie diese 5 Bits 11 Position nach links: 0x1f << 11

Jetzt haben wir eine Maske für die Bits 11 bis 15, die in der ursprünglichen Variablen löschen möchten, das - was wir tun, dass durch den Maske Invertieren bitweise und die Variable mit der invertierten Maske: a & ~(0x1f << 11)

nächstes verschiebt den Wert 17 bis zum 11. Bit: 17 << 11

Dann bitweise wir oder das in die 5 Bits wir haben gelöscht:

unsigned int b = (a & ~(0x1f << 11)) | (17 << 11) 
+2

Ich empfehle, vorzeichenlose Konstanten wie '0x1fu, 17u' zu verwenden – chux

0

Verwenden Sie Bitfelder. Auf diese Weise können Sie Unterabschnitte der Ganzzahl so benennen und darauf zugreifen, als ob sie ganzzahlige Elemente einer Struktur wären.

Für Informationen über C bitfields siehe: https://www.tutorialspoint.com/cprogramming/c_bit_fields.htm

Below-Code, was Sie tun möchten, ist, Bitfelder verwenden. Das "middle5" -Mitglied der Struktur enthält die Bits 11-15. Das Element "low11" ist ein Füllelement für die unteren 11 Bits, so dass das Element "middle5" an der richtigen Stelle ist.

#include <stdio.h> 

void showBits(unsigned int w) 
{ 
    unsigned int bit = 1<<31; 
    while (bit > 0) 
    { 
    printf("%d", ((bit & w) != 0)? 1 : 0); 
    bit >>= 1; 
    } 
    printf("\n"); 
} 

int main(int argc, char* argv[]) 
{ 
    struct aBitfield { 
     unsigned int lower11: 11; 
     unsigned int middle5: 5; 
     unsigned int upper16: 16; 
    }; 

    union uintBits { 
    unsigned int  whole; 
    struct aBitfield parts; 
    }; 

    union uintBits b; 

    b.whole = 17212403u; 

    printf("Before:\n"); 
    showBits(b.whole); 

    b.parts.middle5 = 17; 

    printf("After:\n"); 
    showBits(b.whole);  
} 

Ausgabe des Programms:

Before: 
00000001000001101010001111110011 
After: 
00000001000001101000101111110011 

Natürlich würden Sie sinnvoller Namensgebung für die verschiedenen Felder verwenden möchten.

Seien Sie jedoch vorsichtig, Bitfelder können auf verschiedenen Plattformen unterschiedlich implementiert werden - daher ist es möglicherweise nicht vollständig portabel.

Verwandte Themen