5 Stimmen

Feedback zur Analyse eines Codebeispiels (sichere Codierung)

Ich habe ein Stück Code aus einem Auftrag, bei dem ich mir unsicher bin. Ich bin zuversichtlich, dass ich die Antwort weiß, aber ich möchte mich nur noch einmal bei der Community erkundigen, falls ich etwas vergessen habe. Der Titel ist im Grunde sichere Kodierung und die Frage ist nur, um die Ergebnisse zu erklären.

int main() {
   unsigned int i = 1;
   unsigned int c = 1;
   while (i > 0) {
     i = i*2;
     c++;
   }
   printf("%d\n", c);
   return 0;
}

Meine Argumentation ist folgende:

Auf den ersten Blick könnte man meinen, der Code würde ewig laufen, da er mit einem positiven Wert initialisiert wird und immer größer wird. Das ist natürlich falsch, denn irgendwann wird der Wert so groß werden, dass er einen Integer-Überlauf verursacht. Das wiederum ist auch nicht ganz richtig, weil es die Variable 'i' dazu zwingt, vorzeichenbehaftet zu sein, indem es das letzte Bit auf 1 setzt und somit als negative Zahl angesehen wird, wodurch die Schleife beendet wird. Es wird also nicht in den nicht zugewiesenen Speicher geschrieben und damit ein Integer-Überlauf verursacht, sondern der Datentyp wird verletzt und damit die Schleife abgebrochen.

Ich bin mir ziemlich sicher, dass dies der Grund ist, aber ich möchte es nur noch einmal überprüfen. Hat jemand eine Meinung?

5voto

sharptooth Punkte 162790

No, unsigned int wird niemals gegen Null als vorzeichenbehaftete Zahl verglichen. Die einzige Möglichkeit, die Schleife zu beenden, besteht darin, dass die Variable genau Null wird.

Letzteres wird mit Sicherheit einmal passieren, da Sie bei jeder Iteration mit 2 (einer geraden Zahl) multiplizieren und dies dazu führt, dass ein Null-Bit von rechts eingefügt wird (das am wenigsten aussagekräftige Bit), so dass nach einer gewissen Anzahl von Iterationen alle Nicht-Null-Bits aus der Zahl "herausgeschoben" werden und sie zu Null wird.

2voto

pmg Punkte 102904

Beim Umgang mit vorzeichenlosen Werten gibt es keinen Überlauf. Alle Berechnungen werden modulo durchgeführt (UINT_MAX + 1) .

Was also passiert, ist, dass der Wert durch wiederholtes Multiplizieren mit 2 schließlich auf Null umschlägt ... und Ihre Schleife stoppt

Nehmen wir der Einfachheit halber an, dass unsigned 4 Bit breit ist.

1 * 2 = 2 ==> 0b0010
2 * 2 = 4 ==> 0b0100
4 * 2 = 8 ==> 0b1000
8 * 2 = 0 ==> 0b0000

1voto

Werte ohne Vorzeichen laufen nicht über; sie sind sogar garantiert und so definiert, dass sie sich umdrehen.

1voto

Margus Punkte 18992

Im Falle von signed integer setzt das am weitesten links stehende Bit das Zeichen Der Wertebereich, den dieses Typenelement haben kann, ist also -2147483648 bis 2147483647 . Um aus einem positiven Wert einen negativen Wert zu erhalten, kehren Sie alle Bits um und andersherum.

Im Falle von unsigned integer Das am weitesten links liegende Bit wird zur Speicherung zusätzlicher Werte verwendet. Der Wertebereich, den dieses Element haben kann, ist also 0 bis 4294967295 .

In binärer Form, wenn i=1; und Sie tun nur i = i*2; dann sind Werte, die man als Werte haben kann:

1 // 1 in base 10
10 // 2 in base 10
100 // 4 in base 10
1000
10000
100000
1000000
10000000
100000000
1000000000
10000000000
100000000000
1000000000000
10000000000000
100000000000000
1000000000000000
10000000000000000
100000000000000000
1000000000000000000
10000000000000000000
100000000000000000000
1000000000000000000000
10000000000000000000000
100000000000000000000000
1000000000000000000000000
10000000000000000000000000
100000000000000000000000000
1000000000000000000000000000
10000000000000000000000000000
100000000000000000000000000000
1000000000000000000000000000000 // 1073741824 in base 10
10000000000000000000000000000000 // 2147483648 in base 10 

Wenn Sie nun eine Schleife haben wie: while (i > 0) { y i sich wie oben beschrieben verhält, dann befindet es sich in einer Endlosschleife, da es nie 0 sein wird. Es kommt zu Überläufen, aber das Programm wird dadurch nicht gebremst - es läuft weiter.

Falls variabel i vorzeichenbehaftet ist (Standard), dann erhalten Sie die Ausgabe c=32 als ganze Zahl 10000000000000000000000000000000 ergibt -2147483648 und das ist < 0 . In diesem Fall kennen Sie jedoch den Ausgang nicht.

Da es sich um eine Schularbeit handelt, haben sich die Lehrer natürlich ein Problem ausgesucht, bei dem man aus der Ausführung des bereitgestellten Codes nichts schließen kann. Ich gehe davon aus, dass das so ist, weil sie wollen, dass man weiß, wie unterliegende Typen gespeichert werden und was der Unterschied zwischen Typen mit und ohne Vorzeichen ist.

Nur als zusätzliche Information: Java hat keine vorzeichenlosen Primitive oder unveränderliche Zahlenklassen. Sie nicht zu haben, kann in manchen Fällen schmerzhaft sein. Es ist zweifelsohne ein nützliches Schlüsselwort.

0voto

Erik Punkte 85308

I ist durchgehend vorzeichenlos. Irgendwann wird es überlaufen (oder umschlagen, wenn das es klarer macht) und genau 0 werden, es kann niemals negativ sein.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X