Wann sollten vorzeichenlose Werte gegenüber vorzeichenbehafteten Werten verwendet werden?

81

Wann ist es angebracht, eine vorzeichenlose Variable gegenüber einer vorzeichenbehafteten zu verwenden? Was ist mit einer forSchleife?

Ich höre viele Meinungen darüber und wollte sehen, ob es etwas gibt, das einem Konsens ähnelt.

for (unsigned int i = 0; i < someThing.length(); i++) {  
    SomeThing var = someThing.at(i);  
    // You get the idea.  
}

Ich weiß, dass Java keine vorzeichenlosen Werte hat, und das muss eine bewusste Entscheidung von Sun Microsystems gewesen sein.

Bernard
quelle
1
Ich fand das hilfreich: codemines.blogspot.ca/2007/10/…
mk12
Ich denke, diese Frage basiert auf Meinungen. Der dargestellte Code wird in beiden Fällen einwandfrei ausgeführt, sodass Sie beide verwenden können. Abgesehen von Leistungsgründen (keine Antwort befasst sich bisher tatsächlich mit Leistung) ist es nur persönlicher Geschmack.
Trilarion

Antworten:

69

Ich war froh, ein gutes Gespräch zu diesem Thema zu finden, da ich vorher nicht wirklich darüber nachgedacht hatte.

Zusammenfassend ist signiert eine gute allgemeine Wahl - selbst wenn Sie absolut sicher sind, dass alle Zahlen positiv sind -, wenn Sie die Variable arithmetisch ausführen möchten (wie in einem für Schleifen typischen Fall).

Wenn Sie bitweise Dinge wie Masken tun, macht unsigniert mehr Sinn. Oder wenn Sie unbedingt diesen zusätzlichen positiven Bereich erreichen möchten, indem Sie das Vorzeichenbit nutzen.

Persönlich mag ich es, unterschrieben zu sein, weil ich mir nicht traue, konsistent zu bleiben und es zu vermeiden, die beiden Typen zu vermischen (wie der Artikel warnt).

saint_groceon
quelle
3
Später in diesem Thread wird gezeigt, dass unsignedes für die Erkennung von Überläufen in nicht vertrauenswürdigen Eingaben weit überlegen ist. Leider sind die vorgeschlagenen "Antworten" auf das Rätsel nicht so toll. Meins ist, template<size_t limit> bool range_check_sum( unsigned a, unsigned b ) { return (a < limit) && (b < limit - a); } wenn jemand eine ähnlich einfache und unkomplizierte Antwort mit signierten Typen hat, würde ich sie gerne sehen.
Ben Voigt
10

In Ihrem obigen Beispiel wäre unsigned nützlich, wenn 'i' immer positiv ist und ein höherer Bereich von Vorteil wäre. Zum Beispiel, wenn Sie Anweisungen zum Deklarieren verwenden, z. B.:

#declare BIT1 (unsigned int 1)
#declare BIT32 (unsigned int reallybignumber)

Besonders wenn sich diese Werte nie ändern werden.

Wenn Sie jedoch ein Buchhaltungsprogramm durchführen, bei dem die Leute mit ihrem Geld unverantwortlich sind und ständig rote Zahlen schreiben, sollten Sie auf jeden Fall "signiert" verwenden.

Ich stimme dem Heiligen jedoch zu, dass eine gute Faustregel darin besteht, signiert zu verwenden, was C standardmäßig verwendet, damit Sie abgesichert sind.

Halloandre
quelle
9

Ich würde denken, wenn Ihr Geschäftsfall vorschreibt, dass eine negative Zahl ungültig ist, möchten Sie , dass ein Fehler angezeigt oder ausgelöst wird.

Vor diesem Hintergrund habe ich erst kürzlich bei der Arbeit an einem Projekt, bei dem Daten in einer Binärdatei verarbeitet und in einer Datenbank gespeichert werden, von vorzeichenlosen Ganzzahlen erfahren. Ich habe die Binärdaten absichtlich "verfälscht" und am Ende negative Werte anstelle eines erwarteten Fehlers erhalten. Ich stellte fest, dass der Wert, obwohl er konvertiert wurde, für meinen Business Case nicht gültig war.
Mein Programm ist nicht fehlerhaft und ich habe falsche Daten in die Datenbank aufgenommen. Es wäre besser gewesen, wenn ich uintdas Programm verwendet hätte und fehlgeschlagen wäre.

Keith Sirmons
quelle
8

C- und C ++ - Compiler generieren eine Warnung, wenn Sie signierte und nicht signierte Typen vergleichen. In Ihrem Beispielcode konnten Sie Ihre Schleifenvariable nicht ohne Vorzeichen setzen und den Compiler ohne Warnungen Code generieren lassen (vorausgesetzt, diese Warnungen waren aktiviert).

Natürlich kompilieren Sie mit Warnungen, die ganz aufgedreht sind, oder?

Und haben Sie darüber nachgedacht, mit "Warnungen als Fehler behandeln" zu kompilieren, um noch einen Schritt weiter zu gehen?

Der Nachteil bei der Verwendung von vorzeichenbehafteten Zahlen besteht darin, dass die Versuchung besteht, sie zu überladen, sodass beispielsweise die Werte 0-> n die Menüauswahl sind und -1 bedeutet, dass nichts ausgewählt ist, anstatt eine Klasse mit zwei Variablen zu erstellen, eine bis Geben Sie an, ob etwas ausgewählt ist, und ein anderes, um diese Auswahl zu speichern. Bevor Sie es wissen, testen Sie überall auf negative und der Compiler beschwert sich darüber, wie Sie die Menüauswahl mit der Anzahl Ihrer Menüoptionen vergleichen möchten - aber das ist gefährlich, weil es sich um verschiedene Typen handelt . Also tu das nicht.

Josh
quelle
6

size_tist oft eine gute Wahl dafür oder size_typewenn Sie eine STL-Klasse verwenden.

Mark Harrison
quelle
Nur wenn Sie mit der Größe von etwas in Bytes zu tun haben.
mk12
@ mk12 Standardbibliothekscontainer machen das size_typeMitglied für die Anzahl der Elemente verfügbar , nicht nur für Bytes. Es sollte anstelle von std::size_tverfügbar verwendet werden, aber es ist ungenau zu implizieren, dass alles, was mit beginnt, size_tnur Bytes bedeuten kann.
underscore_d