Was ist der beste Weg, um eine umgekehrte ‘for’-Schleife mit einem vorzeichenlosen Index auszuführen?
Lesezeit: 3 Minuten
Auron
Mein erster Versuch von für Schleife umkehren das macht sowas n mal war sowas wie:
for ( unsigned int i = n-1; i >= 0; i-- ) {
...
}
Dies scheitert weil in vorzeichenlose Arithmetiki garantiert immer größer oder gleich Null ist, daher ist die Schleifenbedingung immer wahr. Glücklicherweise warnte mich der gcc-Compiler vor einem „sinnlosen Vergleich“, bevor ich mich fragen musste, warum die Schleife unendlich ausgeführt wurde.
Ich suche nach einer eleganten Möglichkeit, dieses Problem zu lösen, wobei Folgendes zu beachten ist:
Es sollte eine rückwärts gerichtete for-Schleife sein.
Der Schleifenindex sollte vorzeichenlos sein.
n ist eine vorzeichenlose Konstante.
Es sollte nicht auf der ‘obskuren’ Ringarithmetik vorzeichenloser Ganzzahlen basieren.
Irgendwelche Ideen? Vielen Dank 🙂
if n > größter durch int darstellbarer positiver Wert.
– Peter Kirkham
20. März 2009 um 11:38 Uhr
Dann verwenden Sie eine lange. Und wenn Ihr Array für längere Zeit zu groß ist, haben Sie ernsthaftere Probleme als unsigned 🙂
– paxdiablo
20. März 2009 um 11:41 Uhr
Semantik vielleicht? Da ich niemals unter Null sein sollte.
– Auron
20. März 2009 um 11:42 Uhr
Wer hat etwas von einem Array gesagt?
– anon
20. März 2009 um 11:42 Uhr
@Pax: Dies könnte beispielsweise Code für einen 16-Bit-Prozessor sein, bei dem i über 32767 beginnt. Die Verwendung von etwas Größerem als einem unsigned int wäre ineffizient.
– Steve Melnikoff
21. März 2009 um 17:07 Uhr
Schizz
Wie wäre es mit:
for (unsigned i = n ; i-- > 0 ; )
{
// do stuff with i
}
@Auron, n ist normalerweise die Länge eines Arrays, daher möchten Sie in den meisten Fällen nicht i == n.
– Quinmare
20. März 2009 um 12:07 Uhr
Soweit es mich betrifft, ist dies die Standardsprache für Reverse Loop, ich bin überrascht, dass die Leute es noch nie zuvor getroffen haben.
– Bobin
20. März 2009 um 13:33 Uhr
Sie können es sogar als schreiben i --> 0 das wird visuell die Absicht verraten 😉
– Patrick Schlüter
11. Mai 2011 um 8:22 Uhr
@HeathHunnicutt – Ganzzahlarithmetik ohne Vorzeichen hat eine gut definierte “Modulo” -Semantik. Out-of-Bounds-Ergebnisse werden stillschweigend umbrochen.
– Mankarse
16. Oktober 2011 um 9:08 Uhr
@HeathHunnicutt Ganzzahlen ohne Vorzeichen laufen in C nie über oder unter. Nur bei Ganzzahlen mit Vorzeichen haben Unterläufe und Überläufe ein undefiniertes Verhalten. Aus der Norm: unsigned arithmetic does not overflow because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting unsigned integer type..
– Ruslan
3. März 2016 um 5:21 Uhr
for ( unsigned int loopIndex = n; loopIndex > 0; --loopIndex ) {
unsigned int i = loopIndex - 1;
...
}
oder
for ( unsigned int loopIndex = 0; loopIndex < n; ++loopIndex ) {
unsigned int i = n - loopIndex - 1;
...
}
Huch! Ich habe versehentlich einen Kommentar gelöscht, als ich versuchte, meinen eigenen zu löschen. Aus meinem Cache: “Ein klassisches Beispiel für lange Variablennamen, die den Code weniger lesbar machen, IMHO.” — Tut mir leid, ich kann kein Rückgängigmachen finden
– Lou Franco
20. März 2009 um 11:40 Uhr
for ( unsigned int i = n; i != 0; i-- ) {
// do something with i - 1
...
}
Beachten Sie, dass, wenn Sie sowohl C++ als auch C verwenden, die Verwendung von != eine gute Angewohnheit ist, wenn Sie zur Verwendung von Iteratoren wechseln, wo <= usw. möglicherweise nicht verfügbar sind.
Außerdem werden Sie bald eine Endlosschleife bemerken, wenn ein Code innerhalb der Schleife noch weiter abnimmt. (und es ist einfacher darüber nachzudenken)
– xtofl
20. März 2009 um 12:38 Uhr
idz
Warum nicht einfach:
unsigned int i = n;
while(i--)
{
// use i
}
Dies erfüllt alle im Hauptteil der Frage aufgezählten Anforderungen. Es verwendet nichts, was die Codeüberprüfung wahrscheinlich nicht bestehen oder gegen einen Codierungsstandard verstoßen könnte. Der einzige Einwand, den ich dagegen sehen könnte, ist, ob das OP wirklich auf a bestand for Schleife und kein einfacher Weg, um i = (n-1) .. 0 zu erzeugen.
Peter Kirkham
Ich würde eher verwenden
for ( unsigned int i = n; i > 0; ) {
--i;
...
}
Es ist fast dasselbe wie die Antwort von skizz (es fehlt ein letztes unnötiges Dekrement, aber der Compiler sollte das wegoptimieren) und wird die Codeüberprüfung tatsächlich bestehen. Jeder Codierungsstandard, mit dem ich arbeiten musste, hatte eine Nicht-Mutation in der bedingten Regel.
Jetzt dasist ein verstümmeltes for-Konstrukt, das schnell durch eine while-Anweisung ersetzt werden kann! -1 dafür.
– xtofl
20. März 2009 um 12:39 Uhr
xtofl – Nein, keine while-Anweisung. Skizz zeigt den besten Weg. Bei einer while-Anweisung muss ihre Schleifenvariable außerhalb ihres Gültigkeitsbereichs in einer unabhängigen Anweisung deklariert werden.
– Svante
20. März 2009 um 12:55 Uhr
Leider würde die Antwort von Skizz in den meisten Shops nicht über die Codeüberprüfung hinausgehen.
– Peter Kirkham
20. März 2009 um 13:03 Uhr
“No-Mutation in Conditional” – Ich dachte, wir wären Programmierer, keine (Code-)Affen! Regeln sollten dort gebrochen werden, wo der Code darunter leiden würde. Die Verwendung eines ‘i-1’-Indexers ist weitaus schlimmer als eine mutierende Bedingung. Die Reifen, durch die einige dieser Antworten springen, sind einfach hässlich.
– Schizz
20. März 2009 um 14:22 Uhr
Ich stimme zu, dass die Verwendung eines i-1-Indexers schlechter ist.
– Peter Kirkham
20. März 2009 um 14:48 Uhr
vartec
for ( unsigned int i = n; i > 0; i-- ) {
...
i-1 //wherever you've been using i
}
Jetzt dasist ein verstümmeltes for-Konstrukt, das schnell durch eine while-Anweisung ersetzt werden kann! -1 dafür.
– xtofl
20. März 2009 um 12:39 Uhr
xtofl – Nein, keine while-Anweisung. Skizz zeigt den besten Weg. Bei einer while-Anweisung muss ihre Schleifenvariable außerhalb ihres Gültigkeitsbereichs in einer unabhängigen Anweisung deklariert werden.
– Svante
20. März 2009 um 12:55 Uhr
Leider würde die Antwort von Skizz in den meisten Shops nicht über die Codeüberprüfung hinausgehen.
– Peter Kirkham
20. März 2009 um 13:03 Uhr
“No-Mutation in Conditional” – Ich dachte, wir wären Programmierer, keine (Code-)Affen! Regeln sollten dort gebrochen werden, wo der Code darunter leiden würde. Die Verwendung eines ‘i-1’-Indexers ist weitaus schlimmer als eine mutierende Bedingung. Die Reifen, durch die einige dieser Antworten springen, sind einfach hässlich.
– Schizz
20. März 2009 um 14:22 Uhr
Ich stimme zu, dass die Verwendung eines i-1-Indexers schlechter ist.
– Peter Kirkham
20. März 2009 um 14:48 Uhr
Vielleicht so? IMHO ist es klar und lesbar. Sie können das if(n>=1) weglassen, wenn es irgendwie implizit bekannt ist.
if(n>=1) {
// Start the loop at last index
unsigned int i = n-1;
do {
// a plus: you can use i, not i-1 here
} while( i-- != 0 );
}
Andere Version:
if(n>=1) {
unsigned int i = n;
do {
i--;
} while( i != 0 );
}
Der erste Code ohne if-Anweisung würde wie folgt aussehen:
unsigned int i = n-1;
do {
} while( i-- != 0 );
14161300cookie-checkWas ist der beste Weg, um eine umgekehrte ‘for’-Schleife mit einem vorzeichenlosen Index auszuführen?yes
if n > größter durch int darstellbarer positiver Wert.
– Peter Kirkham
20. März 2009 um 11:38 Uhr
Dann verwenden Sie eine lange. Und wenn Ihr Array für längere Zeit zu groß ist, haben Sie ernsthaftere Probleme als unsigned 🙂
– paxdiablo
20. März 2009 um 11:41 Uhr
Semantik vielleicht? Da ich niemals unter Null sein sollte.
– Auron
20. März 2009 um 11:42 Uhr
Wer hat etwas von einem Array gesagt?
– anon
20. März 2009 um 11:42 Uhr
@Pax: Dies könnte beispielsweise Code für einen 16-Bit-Prozessor sein, bei dem i über 32767 beginnt. Die Verwendung von etwas Größerem als einem unsigned int wäre ineffizient.
– Steve Melnikoff
21. März 2009 um 17:07 Uhr