Frage

Ich habe dieses Muster gesehen eine Menge in C & C ++ verwendet.

unsigned int flags = -1;  // all bits are true

Ist das eine gute tragbare Art und Weise dies zu erreichen? Oder wird mit 0xffffffff oder ~0 besser?

War es hilfreich?

Lösung

Ich empfehle Ihnen, es genau zu tun, wie Sie gezeigt haben, da es der direkteste ist. Initialisieren, um -1 das funktioniert immer , unabhängig von der tatsächlichen Zeichen Darstellung, während ~ wird manchmal überraschendes Verhalten, weil Sie den rechten Operanden Typen haben müssen. Nur dann werden Sie den höchsten Wert eines unsigned Typ erhalten.

Ein Beispiel für eine mögliche Überraschung, betrachten diese:

unsigned long a = ~0u;

Es wird nicht notwendigerweise speichern, ein Muster mit allen Bits 1 in a. Aber es wird zuerst ein Muster mit allen Bits 1 in einem unsigned int, erstellen und dann zuweisen a. Was passiert, wenn unsigned long mehr Bits hat, ist, dass nicht alle von ihnen sind 1.

Und halten diese ein, die auf einer nicht-Zweierkomplement-Darstellung fehl:

unsigned int a = ~0; // Should have done ~0u !

Der Grund dafür ist, dass ~0 alle Bits zu invertieren hat. Invertierung, die -1 auf einem Zweier-Komplement-Maschine ergeben wird (was der Wert ist, die wir brauchen!), Wird aber nicht Ausbeute -1 auf einer anderen Darstellung. Auf einer Ergänzung Maschine ein, ergibt es Null. So auf einem Komplement Maschine ein, wird die oben a auf Null initialisiert werden.

Das, was Sie verstehen sollten, ist, dass es alles über Werte ist - nicht Bits. Die Variable wird mit einem Wert initialisiert. Wenn in der Initialisierungsliste Sie die Bits der Variablen für die Initialisierung verwendet ändern, wird der Wert entsprechend diesen Bits erzeugt werden. Der Wert, den Sie benötigen, a auf den höchstmöglichen Wert zu initialisieren, ist -1 oder UINT_MAX. Die zweite wird von der Art der a abhängen - Sie ULONG_MAX für eine unsigned long verwenden müssen. Allerdings wird nicht die erste von seiner Art ab, und es ist eine schöne Art, den allerhöchsten Wert zu bekommen.

Wir sind nicht zu sprechen, ob -1 hat alle Bits ein (es muss nicht immer). Und wir sind nicht im Gespräch darüber, ob ~0 hat alle Bits ein (es hat, natürlich).

Aber was wir sprechen ist, was das Ergebnis der initialisierten flags variabel ist. Und für sie, nur -1 wird mit jeder Art und Maschine arbeiten.

Andere Tipps

  • unsigned int flags = -1; ist tragbar.
  • unsigned int flags = ~0; ist, weil es nicht tragbar beruht auf einer Zweierkomplement-Darstellung.
  • unsigned int flags = 0xffffffff; ist nicht tragbar, weil nimmt 32-Bit ints.

Wenn Sie alle Bits in einer Art und Weise durch die C-Standard garantiert festlegen möchten, verwenden Sie die erste.

Ehrlich gesagt denke ich, alle fff ist besser lesbar ist. In Bezug auf die Bemerkung, dass sein ein Antipattern, wenn Sie wirklich, dass alle Bits gesetzt / gelöscht, ich würde behaupten, dass Sie wahrscheinlich in einer Situation, wo man über die Größe der variablen egal wie auch immer, die für so etwas wie Auftrieb nennen würden :: uint16_t, etc.

Eine Art und Weise, die die genannten Probleme vermeidet, ist einfach zu tun:

unsigned int flags = 0;
flags = ~flags;

Tragbare und auf den Punkt.

Ich bin nicht sicher, ob ein unsigned int für Flags ist eine gute Idee, in erster Linie in C ++. Was ist bitset und dergleichen?

std::numeric_limit<unsigned int>::max() ist besser, weil 0xffffffff davon ausgeht, dass unsigned int ist eine 32-Bit-Ganzzahl.

unsigned int flags = -1;  // all bits are true
     

"Ist das ein guter [,] tragbarer Weg dies zu tun?"

Tragbare? Ja .

Gut? Debatable , wie all die Verwirrung auf diesen Thread gezeigt belegt. Als klar genug, dass Ihre Kollegen Programmierer den Code ohne Verwirrung verstehen kann, sollte eine der Dimensionen, die wir für eine gute Code messen.

Auch ist dieses Verfahren anfällig für Compiler-Warnungen . Um die Warnung ohne lähmende Compiler elide, dann würden Sie eine explizite Umwandlung benötigen. Zum Beispiel:

unsigned int flags = static_cast<unsigned int>(-1);

Die explizite Umwandlung erfordert, dass Sie die Aufmerksamkeit auf die Zielart zahlen. Wenn Sie die Aufmerksamkeit auf die Zielart zahlen, dann werden Sie natürlich die Gefahren der anderen Ansätze vermeiden.

Mein Rat wäre, die Aufmerksamkeit auf die Zielart zu zahlen und stellen Sie sicher, es gibt keine impliziten Konvertierungen. Zum Beispiel:

unsigned int flags1 = UINT_MAX;
unsigned int flags2 = ~static_cast<unsigned int>(0);
unsigned long flags3 = ULONG_MAX;
unsigned long flags4 = ~static_cast<unsigned long>(0);

All das ist richtig und offensichtliche für Ihre Kolleginnen und Programmierer.

Und mit C ++ 11 : Wir auto verwenden können jede dieser noch einfacher zu machen:

auto flags1 = UINT_MAX;
auto flags2 = ~static_cast<unsigned int>(0);
auto flags3 = ULONG_MAX;
auto flags4 = ~static_cast<unsigned long>(0);

Ich halte richtig und klar besser als einfach richtig.

-1 in jedem Typ ohne Vorzeichen umzuwandeln ist durch den Standard garantiert in allen-onen zu führen. Die Verwendung von ~0U ist in der Regel schlecht, da 0 hat unsigned int geben und alle Bits eines größeren Typ ohne Vorzeichen nicht füllen, wenn Sie nicht ausdrücklich etwas wie ~0ULL schreiben. Auf vernünftige Systeme sollten, ~0 identisch sein, auf -1 aber da der Standard diejenigen-Ergänzung und Zeichen / Größe Darstellungen erlaubt, streng genommen ist es nicht tragbar ist.

Natürlich ist es immer in Ordnung 0xffffffff zu schreiben, wenn Sie wissen, was Sie brauchen genau 32 Bits, aber -1 hat den Vorteil, dass es auch in jedem Kontext funktionieren wird, wenn Sie die Größe des Typs nicht wissen, wie Makros, arbeiten an mehreren Typen, oder wenn die Größe des Typs variiert je nach Implementierung. Wenn Sie die Art wissen, eine andere sichere Weise alle-onen zu bekommen, ist die Grenze Makros UINT_MAX, ULONG_MAX, ULLONG_MAX, etc.

Persönlich habe ich immer verwenden -1. Es funktioniert immer, und Sie müssen nicht darüber nachdenken.

Ja. Wie in anderen Antworten erwähnt, ist -1 die meisten tragbaren; Es ist jedoch nicht sehr semantische und löst Compiler-Warnungen.

Um diese Probleme zu lösen, versuchen Sie diese einfachen Helfer:

static const struct All1s
{
    template<typename UnsignedType>
    inline operator UnsignedType(void) const
    {
        return static_cast<UnsignedType>(-1);
    }
} ALL_BITS_TRUE;

Verbrauch:

unsigned a = ALL_BITS_TRUE;
uint8_t  b = ALL_BITS_TRUE;
uint16_t c = ALL_BITS_TRUE;
uint32_t d = ALL_BITS_TRUE;
uint64_t e = ALL_BITS_TRUE;

Solange Sie als einer von #include <limits.h> haben Ihre enthält, sollten Sie nur verwenden,

unsigned int flags = UINT_MAX;

Wenn Sie eine lange im Wert von Bits wollen, könnten Sie verwenden

unsigned long flags = ULONG_MAX;

Diese Werte werden garantiert alle Wert Bits des Ergebnisses auf 1, unabhängig davon, wie signierte ganze Zahlen gesetzt haben umgesetzt werden.

Ich würde die -1 Sache nicht. Es ist eher nicht intuitiv (für mich zumindest). Zuweisen von signierten Daten an eine nicht signierte Variable scheint nur eine Verletzung der natürlichen Ordnung der Dinge zu sein.

In Ihrer Situation, verwende ich 0xFFFF immer. (Verwenden Sie die richtige Anzahl von Fs für die variable Größe natürlich.)

[BTW, ich nur sehr selten sehen die -1 Trick in Code der realen Welt getan.]

Außerdem, wenn Sie wirklich über die einzelnen Bits in einem vairable kümmern, wäre es sinnvoll sein, die mit fester Breite uint8_t, uint16_t, uint32_t Typen zu beginnen.

Auf Intel IA-32-Prozessoren ist es OK 0xFFFFFFFF auf ein 64-Bit-Register und erhält die erwarteten Ergebnisse zu schreiben. Dies liegt daran, IA32e (die 64-Bit-Erweiterung auf IA32) unterstützt nur 32-Bit-immediates. In 64-Bit-Befehle 32-Bit-immediates sind vorzeichenerweitert auf 64 Bits.

Das folgende ist illegal:

mov rax, 0ffffffffffffffffh

Im Folgenden legt 64 1s in RAX:

mov rax, 0ffffffffh

Nur der Vollständigkeit halber wird folgender setzt 32 1s im unteren Teil von RAX (aka EAX):

mov eax, 0ffffffffh

Und in der Tat habe ich habe Programme fehlschlagen, wenn ich schreiben wollte 0xffffffff auf ein 64-Bit-Variable, und ich bekam stattdessen eine 0xFFFFFFFFFFFFFFFF. In C würde dies:

uint64_t x;
x = UINT64_C(0xffffffff)
printf("x is %"PRIx64"\n", x);

ist das Ergebnis:

x is 0xffffffffffffffff

Ich dachte, das als Kommentar posten, um alle Antworten, die besagten, dass 0xFFFFFFFF 32 Bits annimmt, aber so viele Menschen beantwortet es ich dachte, ich es als eine separate Antwort hinzufügen würde.

litb Antwort für eine sehr klare Erklärung der Probleme sehen.

Meine Uneinigkeit besteht darin, dass sehr genau genommen gibt es keine Garantien für jeden Fall. Ich weiß nicht, von jeder Architektur, die keinen Wert ohne Vorzeichen von darstellt ‚eine weniger als zwei hoch die Anzahl der Bits‘, wie alle Bits gesetzt, aber hier ist es, was die Norm eigentlich sagt (3.9.1 / 7 Plus Anmerkung 44):

  

Die Darstellungen von integralen Arten sind Werte, die durch Verwendung eines reinen binären Zahlensystem definieren. [Anmerkung 44:] eine Positionsdarstellung für ganze Zahlen, die die binären Ziffern 0 und 1, in denen verwenden die durch aufeinanderfolgende Bits dargestellten Werte sind additiv, mit 1 beginnen und durch aufeinanderfolgende ganzzahlige Potenz von 2 multipliziert, außer vielleicht für das Bit mit die höchste Position.

Damit bleibt die Möglichkeit, für eines des Bits überhaupt etwas zu sein.

Praktisch: Ja

Theoretisch:. Nein

-1 = 0xFFFFFFFF (oder was auch immer Größe ein int auf Ihrer Plattform ist) ist nur mit Zweierkomplementarithmetik wahr. In der Praxis wird es funktionieren, aber es gibt ältere Maschinen gibt (IBM Mainframe, etc.), wo Sie ein tatsächliches Vorzeichenbit haben, anstatt ein Zweierkomplement-Darstellung. Ihre vorgeschlagen ~ 0 Lösung sollte überall funktionieren.

Obwohl die 0xFFFF (oder 0xFFFFFFFF, etc.) kann einfacher sein, zu lesen, kann es Portabilität in Code brechen, die sonst tragbar wären. Betrachten wir zum Beispiel eine Bibliothek Routine zu zählen, wie viele Elemente in einer Datenstruktur haben bestimmte Bits gesetzt (die genauen Bits vom Anrufer angegeben wird). Die Routine kann völlig agnostisch sein, was die Bits repräsentieren, müssen aber noch ein „alle Bits gesetzt“ konstant haben. In einem solchen Fall, -1 wird erheblich besser als ein Hex konstant, da es mit jedem Bit Größe arbeiten.

Die andere Möglichkeit, wenn ein typedef Wert für die Bit-Maske verwendet wird, wäre ~ zu verwenden (bitMaskType) 0; wenn Bitmaske nur zufällig ein 16-Bit-Typ sein, wird dieser Ausdruck haben nur 16 Bits (auch wenn ‚int‘ sonst 32 Bits), aber da 16 Bits alle sein, die erforderlich sind, sollten die Dinge in Ordnung sein zur Verfügung gestellt , dass man tatsächlich die geeignete Art in der Typumwandlung verwendet wird.

Im übrigen Ausdrücke der Form longvar &= ~[hex_constant] hat einen fiesen Gotcha, wenn die Hex-Konstante zu groß ist in einem int zu passen, wird aber in einem unsigned int passen. Wenn ein int 16 Bits, dann longvar &= ~0x4000; oder longvar &= ~0x10000; wird ein Bit longvar klar, aber longvar &= ~0x8000; wird Bit 15 und alle Bits darüber ausräumen. Werte, die in int passt der Komplement-Operator, um einen Typ int angewandt, aber das Ergebnis wird sein Vorzeichen long verlängert, um die oberen Bits einstellen. Werte, die zu groß für unsigned int sind die Komplement-Operator haben angewendet long einzugeben. Werte, die zwischen diesen Größen sind jedoch den Komplement-Operator gelten unsigned int eingeben, die dann long ohne Vorzeichen eingeben umgewandelt werden.

Wie andere erwähnt haben, -1 ist der richtige Weg, um eine ganze Zahl zu erzeugen, die jedoch mit allen Bits auf 1 gesetzt, um einen Typen ohne Vorzeichen konvertieren, ist die wichtigste Sache in C ++ ist richtig Typen verwenden. Daher ist die richtige Antwort auf Ihr Problem (das die Antwort auf die Frage enthält, die Sie danach gefragt werden), ist dies:

std::bitset<32> const flags(-1);

Das wird immer die genaue Menge von Bits enthalten, die Sie benötigen. Es konstruiert eine std::bitset mit allen Bits auf 1 aus den gleichen Gründen in anderen Antworten erwähnt eingestellt.

Es ist sicherlich sicher, da -1 immer werden alle verfügbaren Bits gesetzt haben, aber Ich mag ~ 0 besser. -1 macht einfach keinen Sinn für eine unsigned int. 0xFF ... ist nicht gut, weil es auf der Breite des Typs abhängig ist.

Ich sage:

int x;
memset(&x, 0xFF, sizeof(int));

Dies wird Ihnen immer das gewünschte Ergebnis.

auf die Tatsache nutzen, die für einen Typ ohne Vorzeichen alle Bits zu einer Zuordnung entspricht den maximal möglichen Wert für den gegebenen Typ zu nehmen,
und Erweiterung des Anwendungsbereichs der Frage an alle unsigned Integer-Typen:

zuweisen -1 arbeitet für jeden unsigned Integer-Typ (unsigned int, uint8_t, uint16_t , etc.) sowohl für C und C ++.

Als Alternative für C ++, können Sie entweder:

  1. Fügen Sie <limits> und verwenden std::numeric_limits< your_type >::max()
  2. individuellen Template-Funktion schreiben (Dies würde auch eine Plausibilitätsprüfung, also erlauben, wenn der Zieltyp wirklich ein unsigned ist Typ)

könnte Zweck mehr Klarheit sein hinzuzufügen, wie -1 Zuordnung immer einig erläuternden Kommentar benötigen würde.

Eine Art und Weise der Bedeutung etwas deutlicher und noch zu machen, die Art zu wiederholen:

const auto flags = static_cast<unsigned int>(-1);

ja gezeigt die Darstellung ist sehr richtig, als ob wir es andersrum u einen Operator erfordert alle Bits zu umkehren, aber in diesem Fall ist die Logik ist ganz einfach, wenn man die Größe der ganzen Zahlen in der Maschine betrachten

beispielsweise in den meisten Maschinen ist eine ganze Zahl 2 Bytes = 16 Bits Maximalwert halten kann, ist es 2 ^ 16-1 = 65535 2 ^ 16 = 65536

0% 65536 = 0 -1% 65.536 = 65.535, die bis 1111 ............. 1 und alle Bits auf 1 gesetzt sind corressponds (wenn wir Restklassen mod 65536 betrachten) daher ist es sehr einfach.

Ich denke

Nein, wenn u diesen Begriff halten es perfekt für unsigned ints ist zu speisen und es tatsächlich funktioniert out

nur überprüfen Sie das folgende Programmfragment

int main () {

unsigned int a=2;

cout<<(unsigned int)pow(double(a),double(sizeof(a)*8));

unsigned int b=-1;

cout<<"\n"<<b;

getchar();

return 0;

}

Antwort für b = 4294967295 Whcih ist -1% 2 ^ 32 auf 4-Byte-Zahlen

daher ist es durchaus möglich, ganze Zahlen ohne Vorzeichen

im Fall von Abweichungen plzz Bericht

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top