2009-12-06 3 views
5

Gibt es einen Nachteil für die Verwendung char für kleine ganze Zahlen in C? Gibt es andere Vorteile als den Belegungs-/Speichervorteil?Vorteile/Nachteile für die Verwendung von char für kleine ganze Zahlen in C

Insbesondere ist der Prozessor wahrscheinlich mit Integer-Arithmetik auf einem char besser oder schlechter als wäre es auf eine (long/short) int fertig zu werden?

Ich weiß, dass dies Prozessor/System/Compiler spezifisch sein wird, aber ich hoffe auf eine Antwort im allgemeinen Fall, oder zumindest der allgemeine Fall für 32-Bit Windows und Solaris, die Systeme I ' m arbeite gerade an. Ich gehe auch davon aus, dass Dinge wie Überlauf/Wraparound-Probleme bereits behandelt wurden.

Update: Visual Studio 6.0 hat nicht wirklich stdint.h wie von Christoph vorgeschlagen. Ein kleines Benchmarking unter Windows (VS 6.0, debug build, 32-bit) mit einer Handvoll gestapelter Loops ergibt int und long als eine ähnliche Leistung, die etwa doppelt so schnell ist wie char. Das Ausführen des gleichen Tests unter Linux mit gcc in ähnlicher Weise pegs int und long als ähnlich, und beide schneller als char, obwohl der Unterschied weniger ausgeprägt ist.

Als Seite beachten, ich habe nicht viel Zeit auf der Suche, verbrachte aber the first implementation of stdint.h for VS 6.0 I found (via Wikipedia) definiert als unsigned char trotz dieser scheinbar zumindest in meinen Tests langsamer. Also die Moral der Geschichte, wie Christoph zu Recht anmerkte: immer Benchmark!

Antwort

12

C99 hat sogenannte "schnellste" Integer-Typen mit minimaler Breite hinzugefügt, um dieses Problem zu lösen. Für den Bereich, der Sie interessiert, wären die Typen int_fast8_t und , die in stdint.h gefunden werden können.

Denken Sie daran, dass es möglicherweise keinen Leistungszuwachs gibt (die Erhöhung des Speicherverbrauchs könnte sogar die Geschwindigkeit verringern); Wie immer, Benchmark! Optimieren Sie nicht vorzeitig oder ausschließlich auf möglicherweise fehlerhafte Annahmen, was funktionieren sollte.

+0

Das ist sehr nützlich, ich wusste nichts über diese, danke! –

+0

gut zu sehen, eine Antwort, die auf den Standard schneidet, gute Arbeit –

+0

Wenn Sie sich um Portabilität kümmern (wie ich, wo ich Code zwischen eingebettetes Ziel und PC freigeben) verwenden Sie keine schnellen Typen, um wirklich etwas zu "speichern" (Klassenmitglieder, Strukturelemente usw.). Verwenden Sie schnelle Typen zum Iterieren, zum Zugriff auf Arrays oder als lokale Cache-Variable. – MaR

6

Nun, das erste Problem ist, dass es nicht durch die C-Standard definiert ist, ob schlicht char signiert oder unsigniert - so dass der einzige Bereich, den Sie portably auf ist verlassen können 0 bis 127

Anders als das im Allgemeinen int soll der Typ sein, der der nativen Wortgröße der Architektur entspricht (aber natürlich wird dies durch nichts erzwungen). Dies wäre tendenziell der Typ mit der besten Rechenleistung, aber das ist alles, was Sie sagen können.

Beachten Sie, dass Operanden, die schmaler als int sind, entweder während der Ausdruckauswertung entweder auf int oder unsigned int erweitert werden.

+0

yep, mir wurde gesagt, dass ein Int die Größe eines Prozessorregisters hat, also wenn Sie ein Zeichen verwenden, wird das Register nicht voll sein, aber immer noch die gleiche Zeit benutzen, um grundlegende Operationen zu machen oder nicht. – Aif

+1

Darüber hinaus wäre int8_t und uint8_t besser als char zu verwenden. –

+0

@Aif: Soweit ich weiß, dauert es sogar * mehr * Zeit, um die Up/Down-Konvertierung durchzuführen. –

0

Die Hauptbetrug, die ich sehen würde, ist, dass Ihr Code einen Typ verwendet, der eine Sache für Werte bedeutet, die etwas anderes bedeuten - z. B. gibt es ein semantisches Problem, das ein Wartungsproblem sein könnte. Wenn du es getan hast, würde ich wahrscheinlich empfehlen es typedefing:

typedef char REALLYSHORT; 

Auf diese Weise A) Es ist klarer, was du tust, und B) Sie können es leicht ändern (zB nur die eine Stelle), wenn Sie geraten in Schwierigkeiten.

Haben Sie eine wirklich guten Grund nicht zu verwenden int?

+0

Ihr semantischer Punkt wird bereits an dem einzigen Ort verwendet, an dem ich dies implementiert habe. Und nein, ich habe keinen guten Grund, ich bin nur neugierig, ob es einen Unterschied macht. –

3

Ein weiterer Con, den ich denken kann ist, dass (so weit ich weiß) "moderne" Prozessoren alle ihre Mathematik in "full" Ganzzahlen, in der Regel 32 Bits. Eine char zu behandeln, bedeutet normalerweise, ein einzelnes Byte aus dem Speicher zu ziehen, mit 0's in ein Register zu füllen, etwas damit zu tun und dann nur die niedrigstwertigen Bits des Ergebnisses zurück in den Speicher zu drücken. Insbesondere, wenn die char nicht an einer handlichen Grenze ausgerichtet ist, erfordert dieser Speicherzugriff viel mehr Arbeit.

char für int Verwendung ist nur sinnvoll, wenn Sie einen viele von Zahlen haben (das heißt eine große Auswahl), und Sie müssen um Platz zu sparen.

+1

Zeichen erfordern weniger Cachezeilenfüllungen und passen besser in den Cache. – HaltingState

2

Intern führen Prozessoren im Allgemeinen Arithmetik auf Maschinenwörtern durch. Dies bedeutet, dass, wenn Berechnungen mit anderen Typen durchgeführt werden, obwohl die Berechnung selbst die gleiche Zeitdauer benötigt, abhängig von dem verfügbaren Befehlssatz möglicherweise zusätzliche Arbeit geleistet werden muss, um Eingaben zu lesen und Berechnungsergebnisse in den Zieltyp (z Vorzeichenerweiterung/Nullfüllung, Verschieben/Maskieren, um nicht ausgerichtete Speicherzugriffe usw. zu vermeiden.

Deshalb definiert C Typen und Operationen wie es tut - die Größe int ist nicht durch den Standard vorgeschrieben, so dass Compiler-Autoren es einem Maschinenwort entsprechen lassen, und Ausdrucksauswertung wird definiert, um kleinere Integer-Typen zu fördern int, wodurch die Anzahl der Punkte, bei denen Ergebnisse zu einem bestimmten Zieltyp gezwungen werden müssen, stark reduziert wird.

Gültige Gründe für die Verwendung von char zum Speichern ganzer Werte sind, wenn der Speicherplatz wirklich so wichtig ist (nicht so oft, wie Sie vielleicht denken) und bei der Beschreibung eines externen Datenformats/Protokolls, zu dem Daten übertragen werden. Erwarten Sie die Verwendung von char, um einen leichten Leistungsverlust zu erleiden, insbesondere auf Hardware wie Cell SPU, wo nur Maschinenwortgrößenspeicherzugriffe verfügbar sind, so dass der Zugriff auf ein Zeichen im Speicher mehrere Verschiebungen und Masken erfordert.

3

Arithmetik auf Zeichen wird fast sicher tatsächlich mit den gleichen Registern als Arithmetik auf Ints durchgeführt. Zum Beispiel:

char c1 = 1; 
char c2 = c1 + 2; 

Der Zusatz stellt die folgenden mit VC++:

00401030 movsx  eax,byte ptr [ebp-4] 
00401034 add   eax,2 
00401037 mov   byte ptr [ebp-0Ch],al 

wo eax ein 32-Bit-Register ist.

Es gibt daher keinen Vorteil für die Verwendung von Zeichen über Bits, wenn es um Rechenleistung geht.

+3

Ja, aber ist der Zugriff auf ein Byte aufgrund von Ausrichtungsproblemen nicht langsamer? Die Tatsache, dass der Zugriff eine einzelne Zeile von ASM ist, bedeutet nicht, dass nicht mehr Mikrocode ausgeführt wird. Hast du einen Einblick darauf? –

+0

Schuldig wie aufgeladen vielleicht zu viel Vereinfachung beim "Ausfüllen mit Nullen" und "Einquetschen in ein Byte". Aber ich glaube, dass so etwas auf einer gewissen Ebene passiert. –

+0

Ich habe keine Ahnung von den Buszugriffszeiten (was ich für das wahre Problem halte) für moderne Prozessoren, fürchte ich - ich habe die Frage nach der Rechenleistung beantwortet. –

Verwandte Themen