Wie man (am elegantesten) genau einstellt n
niedrigstwertige Bits von uint32_t
? Das heißt, eine Funktion zu schreiben void setbits(uint32_t *x, int n);
. Funktion sollte jeden behandeln n
aus 0
zu 32
.
Besonders wertvoll n==32
gehandhabt werden soll.
Hier ist eine Methode, die keine Arithmetik erfordert:
~(~0u << n)
Wenn Sie die niederwertigsten n Bits meinten:
((uint32_t)1 << n) - 1
Auf den meisten Architekturen funktioniert dies nicht, wenn n 32 ist, daher müssen Sie möglicherweise einen Sonderfall dafür festlegen:
n == 32 ? 0xffffffff : (1 << n) - 1
Auf einer 64-Bit-Architektur besteht eine (wahrscheinlich) schnellere Lösung darin, nach oben und dann nach unten zu werfen:
(uint32_t)(((uint64_t)1 << n) - 1)
Tatsächlich kann dies auf einer 32-Bit-Architektur sogar schneller sein, da Verzweigungen vermieden werden.
Die anderen Antworten behandeln den Sonderfall von nicht n == 32
(Verschieben um größer oder gleich der Breite des Typs ist UB), also hier ist eine bessere Antwort:
(uint32_t)(((uint64_t)1 << n) - 1)
Alternative:
(n == 32) ? 0xFFFFFFFF : (((uint32_t)1 << n) - 1)
const uint32_t masks[33] = {0x0, 0x1, 0x3, 0x7 ...
void setbits(uint32_t *x, int n)
{
*x |= masks[n];
}
Wenn Sie die höchstwertigen n Bits meinen:
-1 ^ ((1 << (32 - n)) - 1)
Wenn n null ist, sollten basierend auf der Frage keine Bits gesetzt werden.
const uint32_t masks[32] = {0x1, 0x3, 0x7, ..., 0xFFFFFFFF};
void setbits(uint32_t *x, int n)
{
if ( (n > 0) && (n <= 32) )
{
*x |= masks[--n];
}
}
Ziele:
- keine Verzweigungen (einschließlich Parameterprüfung von n)
- keine 64-Bit-Konvertierungen
void setbits(uint32_t *x, unsigned n) {
// As @underscore_d notes in the comments, this line is
// produces Undefined Behavior for values of n greater than
// 31(?). I'm ok with that, but if you're code needs to be
// 100% defined or you're using some niche, little-used
// compiler (perhaps for a microprocesser?), you should
// use `if` statements. In fact, this code was just an
// an experiment to see if we could do this in only 32-bits
// and without any `if`s.
*x |= (uint32_t(1) << n) - 1;
// For any n >= 32, set all bits. n must be unsigned
*x |= -uint32_t(n>=32);
}
Hinweis: Wenn Sie brauchen n
Typ sein int
fügen Sie dies am Ende hinzu:
// For any n<=0, clear all bits
*x &= -uint32_t(n>0);
Erläuterung:
*x |= -uint32_t(n>=32);
Wann n>=32
ist wahr, x
wird mit 0xFFFFFFFF bitweise ODER-verknüpft, was ein ergibt x
mit allen Bits gesetzt.
*x &= -uint32_t(n>0);
Diese Zeile besagt, dass solange irgendein Bit gesetzt sein soll, n>0
bitweises UND x
mit 0xFFFFFFFF, was zu keiner Änderung führt x
. Wenn n<=0
, x
werden bitweise mit 0 UND-verknüpft und ergeben folglich den Wert 0.
Beispielprogramm, um zu zeigen, dass der Algorithmus funktioniert:
#include <stdio.h>
#include <stdint.h>
void print_hex(int32_t n) {
uint32_t x = (uint32_t(1) << n);
printf("%3d: %08x |%08x |%08x &%08x\n",
n, x, x - 1,
-uint32_t(n>=32),
-uint32_t(n>0));
}
void print_header() {
// 1: 00000002 |00000001 |00000000 &ffffffff
printf(" n: 1 << n (1<<n)-1 n >= 32 n <= 0\n");
}
void print_line() {
printf("---------------------------------------------\n");
}
int main() {
print_header();
print_line();
for (int i=-2; i<35; i++) {
print_hex(i);
if (i == 0 || i == 31) {
print_line();
}
}
return 0;
}
Ausgabe (aufgebrochen und kommentiert):
Zum n < = 0
der letzte Schritt UND mit 0, um sicherzustellen, dass das Ergebnis 0 ist.
n: 1 << n (1<<n)-1 n >= 32 n <= 0
---------------------------------------------
-2: 40000000 |3fffffff |00000000 &00000000
-1: 80000000 |7fffffff |00000000 &00000000
0: 00000001 |00000000 |00000000 &00000000
Zum 1 <= n <= 31
, die letzten beiden Schritte “OR 0, AND 0xffffffff” bewirken keine Änderung der Zahl. Der einzige Schritt, der zählt, ist das “ODER (1<
n: 1 << n (1<<n)-1 n >= 32 n <= 0
---------------------------------------------
1: 00000002 |00000001 |00000000 &ffffffff
2: 00000004 |00000003 |00000000 &ffffffff
3: 00000008 |00000007 |00000000 &ffffffff
4: 00000010 |0000000f |00000000 &ffffffff
5: 00000020 |0000001f |00000000 &ffffffff
6: 00000040 |0000003f |00000000 &ffffffff
7: 00000080 |0000007f |00000000 &ffffffff
8: 00000100 |000000ff |00000000 &ffffffff
9: 00000200 |000001ff |00000000 &ffffffff
10: 00000400 |000003ff |00000000 &ffffffff
11: 00000800 |000007ff |00000000 &ffffffff
12: 00001000 |00000fff |00000000 &ffffffff
13: 00002000 |00001fff |00000000 &ffffffff
14: 00004000 |00003fff |00000000 &ffffffff
15: 00008000 |00007fff |00000000 &ffffffff
16: 00010000 |0000ffff |00000000 &ffffffff
17: 00020000 |0001ffff |00000000 &ffffffff
18: 00040000 |0003ffff |00000000 &ffffffff
19: 00080000 |0007ffff |00000000 &ffffffff
20: 00100000 |000fffff |00000000 &ffffffff
21: 00200000 |001fffff |00000000 &ffffffff
22: 00400000 |003fffff |00000000 &ffffffff
23: 00800000 |007fffff |00000000 &ffffffff
24: 01000000 |00ffffff |00000000 &ffffffff
25: 02000000 |01ffffff |00000000 &ffffffff
26: 04000000 |03ffffff |00000000 &ffffffff
27: 08000000 |07ffffff |00000000 &ffffffff
28: 10000000 |0fffffff |00000000 &ffffffff
29: 20000000 |1fffffff |00000000 &ffffffff
30: 40000000 |3fffffff |00000000 &ffffffff
31: 80000000 |7fffffff |00000000 &ffffffff
Zum n >= 32
, sollten alle Bits gesetzt sein und der “OR ffffffff”-Schritt bewerkstelligt dies unabhängig davon, was der vorherige Schritt getan haben mag. Das n <= 0
step ist dann auch ein noop mit AND ffffffff
.
n: 1 << n (1<<n)-1 n >= 32 n <= 0
---------------------------------------------
32: 00000001 |00000000 |ffffffff &ffffffff
33: 00000002 |00000001 |ffffffff &ffffffff
34: 00000004 |00000003 |ffffffff &ffffffff
Meinst du mit zuletzt hohe oder niedrige Ordnung?
– Jim Rhodes
14. November 2011 um 21:52 Uhr
Diese Frage verarbeitet alle Werte im Bereich [0, 64]: Erstellen einer Maske mit N niederwertigsten Bits gesetzt
– phuklv
19. Juli 2019 um 5:00 Uhr