Ich habe den folgenden Code in diesem Quora-Beitrag gesehen :
#include <stdio.h>
struct mystruct { int enabled:1; };
int main()
{
struct mystruct s;
s.enabled = 1;
if(s.enabled == 1)
printf("Is enabled\n"); // --> we think this to be printed
else
printf("Is disabled !!\n");
}
In C & C ++ ist die Ausgabe des Codes unerwartet .
Ist behindert !!
Obwohl die Erklärung zum "Vorzeichenbit" in diesem Beitrag enthalten ist, kann ich nicht verstehen, wie es möglich ist, dass wir etwas festlegen und es dann nicht so widerspiegelt, wie es ist.
Kann jemand eine ausführlichere Erklärung geben?
Hinweis : Beide Tagsc & c ++sind erforderlich, da sich ihre Standards zur Beschreibung der Bitfelder geringfügig unterscheiden. Siehe Antworten zur C-Spezifikation und C ++ - Spezifikation .
int
ich denke, kann es nur die Werte0
und enthalten-1
.struct mystruct { unsigned int enabled:1; };
?Antworten:
Bitfelder sind vom Standard unglaublich schlecht definiert. Angesichts dieses Codes wissen
struct mystruct {int enabled:1;};
wir nicht :int:n
Gibt an, ob ein Bitfeld als signiert oder nicht signiert anzusehen ist.In Bezug auf den letzten Teil heißt es in C17 6.7.2.1/10:
Nicht normativer Hinweis zur Erläuterung des oben Gesagten:
Wenn das Bitfeld als betrachtet werden soll
signed int
und Sie ein bisschen Größe machen1
, gibt es keinen Platz für Daten, nur für das Vorzeichenbit. Dies ist der Grund, warum Ihr Programm bei einigen Compilern möglicherweise seltsame Ergebnisse liefert.Gute Übung:
int
Typs für jede Form der Bitmanipulation.quelle
Fragen Sie sich, warum es kompiliert oder Ihnen einen Fehler gibt?
Ja, es sollte idealerweise einen Fehler geben. Und das tut es, wenn Sie die Warnungen Ihres Compilers verwenden. In GCC mit
-Werror -Wall -pedantic
:Die Gründe, warum dies der Implementierung überlassen bleibt, im Vergleich zu einem Fehler, haben möglicherweise mehr mit historischen Verwendungen zu tun, bei denen das Erfordernis einer Besetzung bedeuten würde, alten Code zu beschädigen. Die Autoren des Standards glauben möglicherweise, dass Warnungen ausreichten, um die Lücke für die Betroffenen zu schließen.
Um ein wenig Verschreibungspflicht einzubringen, werde ich @ Lundins Aussage wiederholen: "Verwenden Sie niemals Bitfelder für irgendeinen Zweck." Wenn Sie die guten Gründe haben, sich über Ihre Speicherlayoutdetails zu informieren, die Sie zu der Annahme veranlassen würden, dass Sie überhaupt Bitfelder benötigen, werden die anderen damit verbundenen Anforderungen, die Sie mit ziemlicher Sicherheit haben, auf deren Unterspezifikation stoßen.
(TL; DR - Wenn Sie hoch genug sind, um Bitfelder zu "benötigen", sind sie nicht gut genug definiert, um Ihnen zu dienen.)
quelle
char
, der Unterstützung von Bytes, die nicht 8 Bit usw. sind usw. usw. Sie durften schwachsinnigen Computern keinen Marktnachteil verschaffen.Dies ist ein implementierungsdefiniertes Verhalten. Ich gehe davon aus, dass die Maschinen, auf denen Sie dies ausführen, vorzeichenbehaftete Ganzzahlen mit zwei Komplimenten verwenden und
int
in diesem Fall als vorzeichenbehaftete Ganzzahl behandeln, um zu erklären, warum Sie keinen if true-Teil der if-Anweisung eingeben.deklariert
enable
als 1-Bit-Bitfeld. Da es signiert ist, sind die gültigen Werte-1
und0
. Setzen Sie das Feld so,1
dass das Bit, auf das zurückgegangen wird, überläuft-1
(dies ist ein undefiniertes Verhalten).Im Wesentlichen ist beim Umgang mit einem vorzeichenbehafteten Bitfeld der Maximalwert
2^(bits - 1) - 1
der0
in diesem Fall.quelle
-
und+
. Das Komplement von 2 spielt keine Rolle.int
in diesem Fall als unterschrieben. Es ist eine Schande, dass Bitfelder so unterbestimmt sind. Grundsätzlich ist hier diese Funktion, fragen Sie Ihren Compiler, wie man sie verwendet.Man könnte sich vorstellen, dass im Komplementsystem der 2 das Bit ganz links das Vorzeichenbit ist. Jede vorzeichenbehaftete Ganzzahl mit dem am weitesten links stehenden Bit ist daher ein negativer Wert.
Wenn Sie eine 1-Bit-Ganzzahl mit Vorzeichen haben, hat sie nur das Vorzeichenbit. Die Zuweisung
1
zu diesem einzelnen Bit kann also nur das Vorzeichenbit setzen. Beim Zurücklesen wird der Wert als negativ interpretiert, ebenso wie -1.Die Werte, die eine 1-Bit-Ganzzahl mit Vorzeichen enthalten kann, sind
-2^(n-1)= -2^(1-1)= -2^0= -1
und2^n-1= 2^1-1=0
quelle
Gemäß dem C ++ - Standard n4713 wird ein sehr ähnliches Code-Snippet bereitgestellt. Der verwendete Typ ist
BOOL
(benutzerdefiniert), kann jedoch für jeden Typ gelten.Auf den ersten Blick erscheint der fette Teil offen für Interpretationen. Die richtige Absicht wird jedoch klar, wenn die
enum BOOL
von der abgeleitet wirdint
.Mit dem obigen Code wird eine Warnung ausgegeben ohne
-Wall -pedantic
:Die Ausgabe ist:
Wenn dies vereinfacht
enum BOOL : int
wird, erfolgtenum BOOL
die Ausgabe wie in der obigen Standard-Passage angegeben:Daher kann, wie auch nur wenige andere Antworten, gefolgert werden, dass der
int
Typ nicht groß genug ist, um den Wert "1" in nur einem einzelnen Bitbitfeld zu speichern.quelle
Es ist nichts Falsches an Ihrem Verständnis von Bitfeldern, das ich sehen kann. Was ich sehe ist, dass Sie Mystruct zuerst als Struct Mystruct neu definiert haben {int enabled: 1; } und dann als struct mystruct s; . Was Sie hätten codieren sollen, war:
quelle