Sinn und Zweck von int
-
Wozu ist eigentlich der int-Datentyp gut? Sowohl auf 32 Bit, als auch auf 64 Bit ist short 2 Byte lang und long 4 Byte. Aber int ist entweder 2 oder 4 Byte lang. Also kann man doch komplett auf int verzichten, oder irre ich mich da?
-
Der ANSI-STandard macht keine konkreten Aussagen über die absulute Größe der Datentypen, sondern spezifiziert nur, daß sizeof(short)<=sizeof(int)<=sizeof(long) gelten muß (und die Mindestgrößen der Datentypen). Uns afaik stellt int genau die Größe dar, mit der dein Prozessor am besten/schnellsten umgehen kann.
-
Sofern ich mich richtig erinnere, kann man die folgenden Mindestgrössen irgendwie herleiten (aus
<climits>?) Für portable Programmierung können die Typen so eingesetzt werden:signed char/unsigned char-> genau 1 Bytesigned short/unsigned short-> mind. 2 Bytes, spare Speicher auf Kosten der Geschwindigkeitsigned int/unsigned int-> mind. 2 Bytes, spare Rechenzeit auf Kosten des Speicherplatzessigned long/unsigned long-> mind. 4 Bytessigned long long/unsigned long long-> mind. 8 Bytes (erst C++0x)
Im Weiteren zählen
char,wchar_tundboolzu den integralen Typen, welche allerdings nicht primär aufs Rechnen, sondern zur Darstellung von Zeichen und Wahrheitswerten ausgelegt sind. In Boost und C++0x gibts ausserdem den Header<cstdint>mit diversen Typdefs.
-
Tuut schrieb:
Wozu ist eigentlich der int-Datentyp gut? Sowohl auf 32 Bit, als auch auf 64 Bit ist short 2 Byte lang und long 4 Byte. Aber int ist entweder 2 oder 4 Byte lang. Also kann man doch komplett auf int verzichten, oder irre ich mich da?
Falsche Zahlen.
Sowohl auf 16 Bit, als auch auf 32 Bit ist short 2 Byte lang und long 4 Byte. Aber int ist entweder 2 oder 4 Byte lang.
Sowohl auf 32 Bit, als auch auf 64 Bit ist int 4 Byte lang und long long 8 Byte. Aber long ist entweder 4 oder 8 Byte lang.
(Wobei das nicht gesetzlich garantiert ist, sonder nur üblich.)Leider gibt es damit keinen Typ mehr, von dem man stark annehmen sagen kann, daß er die Registerbreite gerade ausschöpft. Schade.
-
volkard schrieb:
Leider gibt es damit keinen Typ mehr, von dem man stark annehmen sagen kann, daß er die Registerbreite gerade ausschöpft. Schade.
Theoretisch dürfte
(u)int_fast16_taus<cstdint>dies erfüllen, oder? Ob er tatsächlich so umgesetzt ist, ist wieder eine andere Frage. Eventuell muss man sich selbst was basteln...
-
long entspricht doch auf praktisch jedem System außer Windows einem Machineword, also Registerbreite ?
-
Ethon schrieb:
long entspricht doch auf praktisch jedem System außer Windows einem Machineword, also Registerbreite ?
Genau das sagte man früher über den int.
-
Nexus schrieb:
volkard schrieb:
Leider gibt es damit keinen Typ mehr, von dem man stark annehmen sagen kann, daß er die Registerbreite gerade ausschöpft. Schade.
Theoretisch dürfte
(u)int_fast16_taus<cstdint>dies erfüllen, oder? Ob er tatsächlich so umgesetzt ist, ist wieder eine andere Frage. Eventuell muss man sich selbst was basteln...Ich würde eher für logisch halten, daß der uint_fast_16_t der kleinste typ ist, der nicht langsamer rechnet als ein typ mit mehr als 16 bit. ich stelle mir maschinen wie frühe pentiums vor, die 32-bittig schneller rechnen konnten als 16-bittig. oder ganz andere maschinen, wo nur 32-bittig geht und 16-bittige rechnungen durch anschließendes &0xffff simuliert werden müssen.
-
Obligatorischer Hinweis, dass ein Byte nur mindestens 8 Bit hat und theoretisch auch größer sein darf. Vor längerer Zeit hat sogar mal jemand ein konkretes Beispiel für einen solchen Rechner genannt.
-
volkard schrieb:
Sowohl auf 32 Bit, als auch auf 64 Bit ist int 4 Byte lang und long long 8 Byte. Aber long ist entweder 4 oder 8 Byte lang.
Nein, das ist falsch.
Die ISO Norm gibt nur Mindestgrößen vor.sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof (long) = sizeof(size_t)Die ISO C++ Norm verweist auf die ISO C Norm für die Datentypengrößen. <limits.h> definiert für
- char min. 8Bit
- short min. 16Bit
- int min. 16Bit
- long min. 32Bit
- long long min. 64Bit
Die ISO Norm für POSIX und die Single UNIX Specification definieren einen 32Bit und einen 64Bit Modus, die als ILP32 bzw. LP64 festgelegt sind. Windows nutzt ILP32 und ILP64.
-
Dann wünsch ich mir für C++0x eben, dass das Mal sinnvoll gemacht wird. Dass dies größer als das ist, ist ja ganz nett, aber wenn ich eben unabhängig von der Größe möglichst performant arbeiten möchte, ist das anscheinend x86-x64-übergreifend nicht geklärt, richtig?
-
Eisflamme schrieb:
Dann wünsch ich mir für C++0x eben, dass das Mal sinnvoll gemacht wird. Dass dies größer als das ist, ist ja ganz nett, aber wenn ich eben unabhängig von der Größe möglichst performant arbeiten möchte, ist das anscheinend x86-x64-übergreifend nicht geklärt, richtig?
Naja, 32 Bit zu verrechnen muss auf 64 Bit nicht unbedingt langsamer sein als 64-Bit Zahlen zu verrechnen. Ich würde sogar eher erwarten, dass es schneller ist. Du kannst davon ausgehen, dass intern ein größerer Datentyp benutzt würde, wenn dieser wesentliche Geschwindigkeitsvorteile böte, siehe dazu auch die short-Debatte. Der Vorteil von 64-Bit Zahlen auf 64-Bit Rechnern ist ja, dass diese nicht so lahm sind wie auf 32-Bit. Dadurch werden die kleineren Zahlen nicht langsamer.
-
Ich verstehe. Und Alignment sorgt z.B. innerhalb von Strukturen für genau das, was Du da beschreibst, oder?
also nur zum Gesamtverständnis für mich, hat nix mit den Datentypen oder dem Thema hier zu tun
-
Eisflamme schrieb:
Ich verstehe. Und Alignment sorgt z.B. innerhalb von Strukturen für genau das, was Du da beschreibst, oder?
Solche Details der Mikrooptimierung überlasse ich dem Compiler. Ich weiß bloß, dass es solche Mechanismen gibt, aber ich weiß nicht genug um qualifizierte Aussagen über die Details zu machen.
Da Geschwindigkeitsoptimierungen aber ein gängiger Schwanzvergleich zwischen verschiedenen Compilern sind, darfst du davon ausgehen, dass solche Details ziemlich optimal umgesetzt werden. Wenn es da etwas zu holen gäbe, würde es auch gemacht.
Ich kann ja mal einen Benchmark machen, während ich meinen Kaffee trinke. Ich melde mich gleich wieder. Aber wenn die 64-Bits gewinnen, würde mich das sehr überraschen.
-
Mich hat nur der Hintergrund von Alignment interessiert, da es für mich gerade logisch erscheint, dass auf Registerbreiten optimiert wird. Alignment hat ja wohl oft 4 Byte, was 32 Bit entspricht. Kompiliert man für 64 Bit, wäre ein Alignment auf 8 Byte wohl logisch.
Benchmarking klingt gut!
-
So, ich habe da was zusammengehackt. Leider erstmal nur für POSIX, da ich gerade keine Zeit hatte, boost::ptime zu lernen:
#include <iostream> #include <ctime> using namespace std; struct Foo { int a; int b; }; struct Bar { long a; long b; }; template<typename T> void waste_time(decltype(T::a) how_much) { typedef decltype(T::a) type; timespec start, end; clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start); T t={12345, 54321}; for(type i=0; i<how_much; ++i) { t.a+=t.b; t.b*=t.b; t.a-=t.b; t.b^=t.a; t.a<<=4; t.b-=t.a; t.a>>=3; t.b+=7; t.a+=t.b; } clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end); cout<<"Anti-Optimierungsausgabe: "<<t.a<<' '<<t.b<<'\n'; long long nano=(end.tv_sec - start.tv_sec) * 1000000000; nano+=(end.tv_nsec - start.tv_nsec); cout<<"Benötigte Nanosekunden: "<<nano<<"\n\n"; } int main() { cout << "Sizeof int: " << sizeof(int) <<'\n' << "Sizeof long: " << sizeof(long) <<'\n' << "Sizeof Foo: " << sizeof(Foo) <<'\n' << "Sizeof Bar: " << sizeof(Bar) <<'\n'; cout<<"\nEine dem Compiler unbekannte Zahl: "; int anti_optimizer_input; cin>>anti_optimizer_input; cout<<"Mit Foo:\n"; waste_time<Foo>(anti_optimizer_input); cout<<"Mit Bar:\n"; waste_time<Bar>(anti_optimizer_input); cout<<"Nochmal mit Foo:\n"; waste_time<Foo>(anti_optimizer_input); cout<<"Nochmal mit Bar:\n"; waste_time<Bar>(anti_optimizer_input); cout<<"10x mit Foo:\n"; waste_time<Foo>(10*anti_optimizer_input); cout<<"10x mit Bar:\n"; waste_time<Bar>(10*anti_optimizer_input); cout<<"10x mit Foo:\n"; waste_time<Foo>(10*anti_optimizer_input); cout<<"10x mit Bar:\n"; waste_time<Bar>(10*anti_optimizer_input); }Die Ergebnisse sind konsistent über viele Läufe auf meinem Core 2:
[b]seppj@irgendwo{~/src}> [/b]g++ test.cc -Wall -std=c++0x -O3 -Wextra -xHost -lrt [b]seppj@irgendwo{~/src}>[/b] ./a.out Sizeof int: 4 Sizeof long: 8 Sizeof Foo: 8 Sizeof Bar: 16 Eine dem Compiler unbekannte Zahl: 10000000 Mit Foo: Anti-Optimierungsausgabe: -1332682501 -1166096675 Benötigte Nanosekunden: 50591275 Mit Bar: Anti-Optimierungsausgabe: -1527253877453168389 -1903512469154904355 Benötigte Nanosekunden: 55345337 Nochmal mit Foo: Anti-Optimierungsausgabe: -1332682501 -1166096675 Benötigte Nanosekunden: 40838216 Nochmal mit Bar: Anti-Optimierungsausgabe: -1527253877453168389 -1903512469154904355 Benötigte Nanosekunden: 55354001 10x mit Foo: Anti-Optimierungsausgabe: -1332682501 -1166096675 Benötigte Nanosekunden: 408339301 10x mit Bar: Anti-Optimierungsausgabe: -1527253877453168389 -1903512469154904355 Benötigte Nanosekunden: 553385774 10x mit Foo: Anti-Optimierungsausgabe: -1332682501 -1166096675 Benötigte Nanosekunden: 408321611 10x mit Bar: Anti-Optimierungsausgabe: -1527253877453168389 -1903512469154904355 Benötigte Nanosekunden: 553377433Klarer Sieg für int. Wer Spaß hat, kann ja noch ein paar Dummy-chars in die structs einsetzen, um das Alignment und Padding zu testen.
-
Und jetzt habe ich das gleiche Programm auf einem i7 ausgeführt und nun sind int und long gleich schnell.
Und wenn ich 32-Bit Code erzeuge gehen die 64-Bit Zahlen total ein und sind 4x so langsam wie die 32 Bit Zahlen.
Short verkackt gegen beide und ist ungefähr 1.8 mal langsamer (auf dem i7)
Schlussfolgerungen:
32 Bit Systeme: 32 Bit Zahlen liegen ganz klar vorne. Offensichtlich.
64 Bit Systeme: Kommt auf das System an, aber 32 Bit Zahlen sind jedenfalls nicht langsamer. Die 64 Bit Zahlen bieten mehr berechnete Stellen pro Zeit (auch offensichtlich), aber wenn man diese Stellen gar nicht benötigt, fährt man im Zweifelsfall mit 32 Bit Zahlen besser
Beide: Short nur wenn man wirklich Speicherplatz sparen muss.
-
~john schrieb:
volkard schrieb:
Sowohl auf 32 Bit, als auch auf 64 Bit ist int 4 Byte lang und long long 8 Byte. Aber long ist entweder 4 oder 8 Byte lang.
...
Wobei das nicht gesetzlich garantiert ist, sonder nur üblich.Nein, das ist falsch.
Warum widersprichst Du hier? Konnte Deiner Erklärung nicht folgen, wo Du nur aus der Norm rausholst, daß es nicht garantiert ist.
-
SeppJ schrieb:
Klarer Sieg für int. Wer Spaß hat, kann ja noch ein paar Dummy-chars in die structs einsetzen, um das Alignment und Padding zu testen.
Kommt das nur mir so vor oder sind die Laufzeiten und Ergebnisse für "mit Foo" und "10x mit Foo" sehr nahe beieinander? Ich hab' zwar keine Ahnung, was deine Funktion eigentlich berechnet, aber zumindest bei der Laufzeit hätte ich da größere Abweichungen erwartet.
-
CStoll schrieb:
SeppJ schrieb:
Klarer Sieg für int. Wer Spaß hat, kann ja noch ein paar Dummy-chars in die structs einsetzen, um das Alignment und Padding zu testen.
Kommt das nur mir so vor oder sind die Laufzeiten und Ergebnisse für "mit Foo" und "10x mit Foo" sehr nahe beieinander? Ich hab' zwar keine Ahnung, was deine Funktion eigentlich berechnet, aber zumindest bei der Laufzeit hätte ich da größere Abweichungen erwartet.
Hast du eine Stelle nicht mitgezählt? Es ist doch fast perfekt ein Faktor 10! Eine bessere Bestatigung kann ich mir gar nicht vorstellen, dass die Funktion das macht was sie soll.edit: Oder meinst du, dass du größere Schwnakungen erwartest? Wieso? Ich messe CPU-Zeit, nicht Realzeit.
-
SeppJ schrieb:
CStoll schrieb:
SeppJ schrieb:
Klarer Sieg für int. Wer Spaß hat, kann ja noch ein paar Dummy-chars in die structs einsetzen, um das Alignment und Padding zu testen.
Kommt das nur mir so vor oder sind die Laufzeiten und Ergebnisse für "mit Foo" und "10x mit Foo" sehr nahe beieinander? Ich hab' zwar keine Ahnung, was deine Funktion eigentlich berechnet, aber zumindest bei der Laufzeit hätte ich da größere Abweichungen erwartet.
Hast du eine Stelle nicht mitgezählt? Es ist doch fast perfekt ein Faktor 10! Eine bessere Bestatigung kann ich mir gar nicht vorstellen, dass die Funktion das macht was sie soll.Sorry, mein Fehler *brille putzen geht*. Eventuell solltest du die Ausgabe besser formatieren, so daß man den Unterschied leichter erkennen kann

(PS: Hat die Berechnung eigentlich einen praktischen Nutzen oder geht es nur darum, dort möglichst viele verschiedenen Ganzzahl-Operationen zu kombinieren?)