Wert des booleschen Typs in C geändert

7

Ich habe bemerkt, dass in C meine boolesche Variable irgendwie auf eine Weise verändert wird, die ich nicht verstehe.

%Vor%

Wenn ich einen Wert von 1 für x und einen beliebigen Wert für y ( 1 in diesem Beispiel) eingib:

%Vor%

Am Ende gibt y den korrekten Originalwert aus, aber x ändert sich magisch in 0 dazwischen!

Dies ist kein Problem, wenn die Eingabe für x 0 ist, da die Ausgaben für sowohl x als auch y wie erwartet ihre jeweiligen ursprünglichen Werte sind.

Bitte erläutern Sie, was vor sich geht!

    
Naturally Upbeat Student 31.08.2017, 10:57
quelle

7 Antworten

8

Sie übergeben die Adresse der booleschen Variablen an scanf() , die eine Variable vom Typ int* erwartet. Dies führt zu undefiniertem Verhalten und Sie können falsche Ergebnisse erhalten oder sogar abstürzen.

Um dieses Problem zu lösen, verwenden Sie das temporäre int , um das Scannen eines booleschen Werts (als int) zu speichern und speichern Sie es anschließend als boolesche Variable.

Demo

%Vor%

Auf der anderen Seite ist das Drucken der Boulan-Variablen eine andere Geschichte, wobei der boolesche Wert ohne Probleme zu int indexiert wird und korrekt gedruckt wird.

    
Filip Kočica 31.08.2017 11:02
quelle
7

A bool ist kein int . Das Lesen mit dem Formatbezeichner %d für int ist ein nicht definiertes Verhalten.

Per 7.21.6.2 Die Funktion fscanf , Absatz 13 des C-Standards :

  

Wenn eine Konvertierungsspezifikation ungültig ist, ist das Verhalten nicht definiert.

Beachten Sie, dass Absatz 9 von 7.21.6.1 Die Funktion fprintf angibt:

  

Wenn eine Konvertierungsspezifikation ungültig ist, lautet das Verhalten   nicht definiert. Wenn ein Argument nicht der richtige Typ für die   entsprechende Umsetzungsspezifikation ist das Verhalten   undefiniert.

Aber das ist für fprintf() , nicht fscanf() . Formatbezeichner sind für die scanf() -Funktionen viel strenger, da es keine Argument-Promotion gibt lässt ein Format wie %d für ein char oder bool "arbeiten", das für einen int -Aufruf in printf() hochgestuft wird. Die scanf() -Funktionen werden an die -Adresse des Arguments übergeben, und wenn die Adresse auf die falsche Größe von dem verweist, was im Formatspezifizierer erwartet wird, führt dies zu undefiniertem Verhalten - wie zum Beispiel unerklärte Änderungen an andere Variable.

    
Andrew Henle 31.08.2017 11:04
quelle
7

OK, zwei Punkte hier.

  1. Die Größe von bool ist implementierungsdefiniert.
  2. Für den Typ bool im Standard ist kein Formatbezeichner definiert.

Während also Scannen der Wert ist, übergeben Sie die Adresse von bool als Argument für %d ist schlecht siehe Hinweis , da der angegebene Typ nicht der ist Gleich wie erwarteter Typ.

Sie können eine Zwischenzahl verwenden, den Wert einscannen und (nach der Validierung oder Umwandlung in true und false MACROs) das Ergebnis zurück an bool type Variable zuweisen.

Bei Drucken kann jedoch ein bool aufgrund der Standardargument-Promotion ein Kandidat für das Argument für %d ohne ein Problem sein.

Hinweis:

%d mit *scanf() erwartet, dass das Argument ein int * ist, stattdessen liefert ein bool* ein undefiniertes Verhalten .

Bezugnehmend auf Kapitel §7.21.6.2, Absatz 10

  

[....] Sofern die Zuordnungsunterdrückung nicht durch * angezeigt wurde, wurde die   Das Ergebnis der Konvertierung wird in das Objekt platziert, auf das das erste Argument folgt   das Argument format , das noch kein Konvertierungsergebnis erhalten hat. Wenn dieses Objekt   hat keinen geeigneten Typ, oder wenn das Ergebnis der Konvertierung nicht dargestellt werden kann   Im Objekt ist das Verhalten nicht definiert.

    
Sourav Ghosh 31.08.2017 11:01
quelle
5

bool ist ein anderer Datentyp als int und wahrscheinlich ein einzelnes Byte.

scanf ist keine typsichere Funktion, Sie sagen es mit dem %d -Konvertierungsspezifizierer, der Zeiger auf ein int erwartet, und scanf hat keine Möglichkeit zu wissen, was Sie haben übergeben pointer to bool anstelle von Zeiger auf ein int . Dann erhalten Sie undefiniertes Verhalten .

clang Compiler generiert Warnung:

%Vor%     
rsp 31.08.2017 11:09
quelle
3

Alle anderen Antworten sind technisch korrekt, helfen dir aber nicht wirklich.

Ihr Hauptproblem ist nicht x oder y, aber die Tatsache, dass Sie nicht in der Lage sind, selbst die einfachsten Programmierprobleme zu debuggen. Dies ist leicht zu beheben - aktivieren Sie Compiler-Warnungen (wenn Sie gcc verwenden, fügen Sie die Option -Wall hinzu). Der Compiler wird Sie über einen Fehler wie diesen und viele weitere informieren. Sie müssen nicht jedes Mal zu stackoverflow kommen:)

    
Erki A 31.08.2017 20:44
quelle
0

Betrachten Sie das folgende Programm

%Vor%

Die Ausgabe:

%Vor%

Nun, zwischen z und s gibt es eine 4 Byte Differenz, die in meinem Fall die Größe von int ist.

Zwischen x und y gibt es nur 1 Byte Unterschied.

Jetzt mit dieser Zeile:

%Vor%

Sie sagen mit dem %d to scanf , dass Sie eine 4 Byte lange Eingabe benötigen, eine int .

Dieser int wird gespeichert im Falle von y von der Adresse 0028FF36 und mit einer Eingabe von 0x0001 wird das zweite Byte, das ein 0 ist, bei 0028FF37 gespeichert. Und das ist die Adresse von x .

Sie können es mit einem anderen Eingabewert überprüfen. Wenn Sie zum Beispiel 65535 an y geben, was 0xFFFF ist, dann wird x 0xF sein, was 255 dezimal ist.

    
Bence Kaulics 31.08.2017 11:14
quelle
0

oder vielleicht (wenn die Eingabezeichenfolge "true" enthält oder 1 ist, wird 1 zurückgegeben - andernfalls 0 )

%Vor%     
PeterJ_01 31.08.2017 11:38
quelle

Tags und Links