Skalare Datentypen - irgendeine Verlässlichkeit?



  • Guten Abend,

    Wie handhabt ihr das mit den einfachen Datentypen? Man kann sich dank dem grosszügigen Standard ja nie sicher sein, wieviele Byte ein Typ einnimt und wie gross dessen Wertebereich ist. 🙄

    Wie kann man so einigermassen portabel programmieren? Es ist ja nicht einmal sichergestellt, dass ein Zeiger eine Integer-Adresse beinhaltet. Auch int könnte theoretisch sehr wenige Zahlen umfassen. Nehmt ihr immer entsprechende unabhängige Typedefs? Oder macht ihr einfach (Static-)Assertions bei den Limits? Ich bin bei mir einfach davon ausgegangen, dass short 65536 und int etwas mehr als 4 Milliarden Zustände haben kann. Aber ich programmiere auch hauptsächlich für mich selber und wechsle den Compiler nicht, von daher ist das nicht so relevant.

    Aber wenn man das wirklich korrekt machen wollte: Welchen Sinn haben dann die skalaren Datentypen noch, wenn man sich ja doch nie sicher sein kann?

    Und weshalb hat der C++-Standard diesbezüglich nicht mehr Vorschriften gemacht? Dass int oft den für die Plattform am besten ausgerichteten Datentypen repräsentiert, ist ja schön und gut, aber etwas vage...



  • mh gute frage

    ich programmiere auch sehr viel (ok, eigendlich nur) für mich selbst und demnach kümmere ich mich auch kaum um kompatiblität

    aber eigendlich sollte der standart so genau sein dass man windows code auch auf linux compilen kann und auch was anständiges rausbekommt
    und naja in den nächsten jahren wird int ja wenn grösser werden statt kleiner und von daher ists ja eigendlich verschmerzbar

    und wenn man mal einen zeiger speichern will sollte man schon klassen dafür haben...



  • Skym0sh0 schrieb:

    und naja in den nächsten jahren wird int ja wenn grösser werden statt kleiner und von daher ists ja eigendlich verschmerzbar

    Ja, die Tendenz stimmt schon. Das heisst trotzdem nicht, dass man sich nicht mehr achten muss...

    Skym0sh0 schrieb:

    und wenn man mal einen zeiger speichern will sollte man schon klassen dafür haben...

    Wie meinst du das? Es gibt Situationen, in denen man nicht um rohe Zeiger herumkommt. Abgesehen davon: Was ändern Klassen, die um einen Zeiger gepackt sind, an der Flexibilität des Wertebereichs beziehungsweise der internen Repräsentation des Speichers?



  • Hmm. Im Buch von Stroustrup sagt er, dass char mindestens 8 Bit hat, short mindestens 16 Bit und long 32 Bit hat. Allerdings habe ich im Standard nichts gefunden, was auf dieser Werte weist.

    Das hier besagt lediglich, dass ein char ( in C++ byte genannt) mindestens 8 Bit haben muss. (wegen dem Character set)

    14882 schrieb:

    1.7 The C+ + memory model [intro.memory]
    1 The fundamental storage unit in the C + + memory model is the byte. A byte is at least large enough to contain
    any member of the basic execution character set and is composed of a contiguous sequence of bits, the
    number of which is implementation-defined. The least significant bit is called the low-order bit; the most
    significant bit is called the high-order bit. The memory available to a C + + program consists of one or more
    sequences of contiguous bytes. Every byte has a unique address.

    Etwas genaueres konnte ich leider nicht finden.



  • boost to the rescue: http://www.boost.org/doc/libs/1_37_0/libs/integer/index.html

    und ab C++0x ist <cstdint> dann ja sogar ein offizieller Header 🙂



  • Naja, aber mir ging es ja eher um die Built-Ins.

    Benutzt ihr trotz allem immer int , short , etc.? Oder bei allen unsigned-Typen size_t ? Oder die <cstdint>- bzw. <stdint.h>-Typen?

    Ich finde es einfach ein wenig fragwürdig, dass die Sprache Typen bereitstellt, von denen erwartet wird, dass man mit ihnen arbeitet, aber gleichzeitig kann man sich dabei nie ganz sicher sein...



  • Nexus schrieb:

    Naja, aber mir ging es ja eher um die Built-Ins.

    Benutzt ihr trotz allem immer int , short , etc.? Oder bei allen unsigned-Typen size_t ? Oder die <cstdint>- bzw. <stdint.h>-Typen?

    size_t, etc. wenn es vom Kontext her Sinn macht.

    Nexus schrieb:

    Ich finde es einfach ein wenig fragwürdig, dass die Sprache Typen bereitstellt, von denen erwartet wird, dass man mit ihnen arbeitet, aber gleichzeitig kann man sich dabei nie ganz sicher sein...

    Du kannst dir sicher sein. Wie schon gesagt. char hat mindestens 8 Bit, short mindestens 16 und long mindestens 32. Sie dürfen natürlich größer sein. Aber das sollte in fast allen Fällen nicht schlimm sein.

    Wenn du int verwendest, wird dir was anderes garantiert. Und zwar, dass (soweit ich mich erinnere) er mindestens so lang wie short ist. Und dass er den nativen Integertyp des Prozessors wiederspiegelt. Also das beste ist, womit der Prozessor umgehen kann (unter der Voraussetzung, dass er halt mit mind. 16-Bit umgehen kann).

    Das ist doch eigentlich recht vernünftig. Eine gewisse Sache ist garantiert, aber es kann auch besser sein.



  • ProgChild schrieb:

    Nexus schrieb:

    Ich finde es einfach ein wenig fragwürdig, dass die Sprache Typen bereitstellt, von denen erwartet wird, dass man mit ihnen arbeitet, aber gleichzeitig kann man sich dabei nie ganz sicher sein...

    Du kannst dir sicher sein. Wie schon gesagt. char hat mindestens 8 Bit, short mindestens 16 und long mindestens 32. Sie dürfen natürlich größer sein. Aber das sollte in fast allen Fällen nicht schlimm sein.

    Ich glaube in dem Fall zwar einmal, dass Stroustrup da nichts falsches geschrieben hat, aber im Standard konnte ich von diesen Werten nichts finden.
    Wie gesagt die einzige Garantie, die ich gefunden habe, ist, dass char mindestens 8 Bit haben muss, damit es das Characterset halten kann.



  • Die Mindestgrößen werden indirekt über die Mindesgrößen von den *_MAX und *_MIN Konstanten aus climits garantiert. SHRT_MAX muss z.B. mindestens 32767 groß sein. Die Mindestgröße für short ist also 16-bit.

    Gruß
    Don06





  • drakon schrieb:

    Ich glaube in dem Fall zwar einmal, dass Stroustrup da nichts falsches geschrieben hat, aber im Standard konnte ich von diesen Werten nichts finden.
    Wie gesagt die einzige Garantie, die ich gefunden habe, ist, dass char mindestens 8 Bit haben muss, damit es das Characterset halten kann.

    Ich hab auch gerade im Standard gewühlt und nichts gefunden. Aber ich hab auch die 800 Seiten nicht komplett gelesen 😃

    Ich hab das aber auch irgenwo gelesen, dass das mit den Variablen so garantiert ist.



  • ProgChild schrieb:

    Wenn du int verwendest, wird dir was anderes garantiert. Und zwar, dass (soweit ich mich erinnere) er mindestens so lang wie short ist. Und dass er den nativen Integertyp des Prozessors wiederspiegelt. Also das beste ist, womit der Prozessor umgehen kann (unter der Voraussetzung, dass er halt mit mind. 16-Bit umgehen kann).

    Das heisst, int sollte man um sicher zu gehen nur nutzen, wenn man gerade so gut short nutzen könnte. Naja, dann habe ich das bisher etwas missachtet. Naja... 😉

    Don06 schrieb:

    Die Mindestgrößen werden indirekt über die Mindesgrößen von den *_MAX und *_MIN Konstanten aus climits garantiert. SHRT_MAX muss z.B. mindestens 32767 groß sein. Die Mindestgröße für short ist also 16-bit.

    Okay. Wo findet man dann die tatsächlichen Grössen? Sind die Werte in <limits> eigentlich immer genau die gleichen wie die in <climits> ?



  • Wie "portabel" willst du denn programmieren und warum interessiert dich das so genau wie groß ein Datentyp ist? Wenn du für normale Windows,Linux oder Mac PCs programmierst, sind die doch sogut wie gleich groß und es ist egal. Wenn du für embedded Hardware programmierst weiß du auch wie groß dort die Datentypen sind. Ich vesteh nicht was da so ein großes Problem ist.



  • sagmal schrieb:

    Wie "portabel" willst du denn programmieren und warum interessiert dich das so genau wie groß ein Datentyp ist?

    Weil es von Vorteil wäre, wenn ich meine Programme nicht mühsam durchforsten und Typen ersetzen müsste, wenn ich sie mal auf einer anderen Plattform zum Laufen bringen will.

    sagmal schrieb:

    Wenn du für normale Windows,Linux oder Mac PCs programmierst, sind die doch sogut wie gleich groß und es ist egal.

    Das würde ich nicht sagen. Meines Wissens haben doch bereits die verschiedenen Compiler/IDEs unterschiedliche Typen. Unterscheiden sich nicht bereits MSVC++ und Code::Blocks, zum Beispiel bezüglich long double ?



  • Nexus schrieb:

    sagmal schrieb:

    Wie "portabel" willst du denn programmieren und warum interessiert dich das so genau wie groß ein Datentyp ist?

    Weil es von Vorteil wäre, wenn ich meine Programme nicht mühsam durchforsten und Typen ersetzen müsste, wenn ich sie mal auf einer anderen Plattform zum Laufen bringen will.

    sagmal schrieb:

    Wenn du für normale Windows,Linux oder Mac PCs programmierst, sind die doch sogut wie gleich groß und es ist egal.

    Das würde ich nicht sagen. Meines Wissens haben doch bereits die verschiedenen Compiler/IDEs unterschiedliche Typen. Unterscheiden sich nicht bereits MSVC++ und Code::Blocks, zum Beispiel bezüglich long double ?

    was für Programme schreibst du denn, dass es so wichtig ist, dass du die Datentypen immer voll ausnutzen kannst und sogar long double brauchst?



  • Aus meinem ersten Post sollte der Beweggrund für diesen Thread ersichtlich sein.



  • Nexus schrieb:

    Und weshalb hat der C++-Standard diesbezüglich nicht mehr Vorschriften gemacht? Dass int oft den für die Plattform am besten ausgerichteten Datentypen repräsentiert, ist ja schön und gut, aber etwas vage...

    Das hängt alles von C ab.
    Aber etwas aus der C++ Norm.
    § 3.9.1 Absatz 2
    kann man folgende Reihenfolge schließen
    sizeof(signed char) <= sizeof(short) <= sizeof(int) <= sizeof(long int)
    Absatz 3 ditto für vorzeichenlose Typen

    Desweiteren ist ISO 9899:2001 § 5.2.4.2.1 zu beachten

    CHAR_BIT >= 8
    SCHAR_MIN <= -127
    SCHAR_MAX >= 127
    UCHAR_MAX >= 255
    SHRT_MIN <= -32767
    SHRT_MAX >= 32767
    USHRT_MAX >= 65535
    INT_MIN <= -32767
    INT_MAX >= 32767
    UINT_MAX >= 65535
    LONG_MIN <= -2147483647
    LONG_MAX >= +2147483647
    ULONG_MAX >= 4294967295
    LLONG_MIN <= -9223372036854775807
    LLONG_MAX >= 9223372036854775807
    ULLONG_MAX >= 18446744073709551615
    

    Wenn diese Aussagen nicht ausreichen, dann muß man sich mit <stdint.h> auseinandersetzen. Es gibt darin Datentypen mit exakten Bitgrößen und Datentypen mit mindestens n-Bitgröße.
    Folgendes muß definiert sein.

    int_least8_t
    int_least16_t
    int_least32_t
    int_least64_t
    uint_least8_t
    uint_least16_t
    uint_least32_t
    uint_least64_t
    

    Falls die Integer-Typen mit 8, 16, 32 und 64Bitgröße als Standardtypen existieren, muß es die folgenden typedefs geben.
    int8_t, uint8_t, ... , int64_t, uint64_t

    Folgendes muß wiederrum definiert sein

    int_fast8_t
    int_fast16_t
    int_fast32_t
    int_fast64_t
    uint_fast8_t
    uint_fast16_t
    uint_fast32_t
    uint_fast64_t
    

    Wenn Dir das nicht genügt, dann kannst Du Dich auf die SUS V3 (Single UNIX Spec V3) beziehen (keine Ahnung was für Garantien Windows macht). Natürlich läuft dann Dein Programm nur noch garantiert auf einer SUS V3 Plattform.

    SUSV3 definiert im Prinzip zwei Laufzeitumgebungen ILP32 und LP64.
    Auszug aus "The UNIX System Today" (SUS V2)
    sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(size_t)
    Die typedefs int8_t, int16_t, int32_t (und korrespondierende uint) sind definiert, falls _POSIX_V6_ILP32_OFFBIG, _POSIX_V6_LP64_OFF64 oder _POSIX_V6_LPBIG_OFFBIG definiert wurden ist auch uint64_t bzw. int64_t definiert.

    ILP32 definiert die Bit größen der Typen wie folgt:
    char 8, short 16, int 32, long 32, pointer 32
    LP64:
    char 8, short 16, int 32, long 64, pointer 64

    Es gibt die Möglichkeit, daß ein 64Bit Type im ILP32 Modus definiert ist, aber das hängt dann von bestimmten Makros ab, dazu bitte die SUS lesen.



  • Vielen Dank für die ausführliche Antwort, ~john! Das ist echt interessant, vieles davon habe ich nicht gewusst.

    Wenn man jetzt char , short und long für Integer nutzt, sollte man die Grösse eigentlich relativ gut eingrenzen können. Ansonsten die <stdint.h>-Typen... Danke für eure Bemühungen!



  • int ist nicht der "native" Datentyp des Prozessors.

    (1) Der Begriff an sich ist schon relativ sinnfrei, weil es dem x86 oder x86-64 egal ist, ob er jetzt mit dem 8, 16, 32 Teil des Registers rechnet. Die Größen sind alle "native" weil sie alle im Assembler direkt als Operand angegeben werden können (es muss nicht zum Beispiel ein 16Bit Wert vorher in ein 32 Bit Register kopiert werden, welches dann mit Nullen aufgefüllt wird).

    (2) Wenn man diesen Begriff trotzdem verwendet, müsste ein int für den x86-64 ja 64 Bit haben, ich kennen keinen Compiler der das so macht. Der g++ und VC++ jedenfalls nicht.



  • Optimizer schrieb:

    int ist nicht der "native" Datentyp des Prozessors.

    (1) Der Begriff an sich ist schon relativ sinnfrei, weil es dem x86 oder x86-64 egal ist, ob er jetzt mit dem 8, 16, 32 Teil des Registers rechnet. Die Größen sind alle "native" weil sie alle im Assembler direkt als Operand angegeben werden können (es muss nicht zum Beispiel ein 16Bit Wert vorher in ein 32 Bit Register kopiert werden, welches dann mit Nullen aufgefüllt wird).

    (2) Wenn man diesen Begriff trotzdem verwendet, müsste ein int für den x86-64 ja 64 Bit haben, ich kennen keinen Compiler der das so macht. Der g++ und VC++ jedenfalls nicht.

    Andersherum wird ein Schuh draus. Compilierst du für einen 16-Bit-Prozessor wird int wohl kaum 32-Bit groß sein. Compilierst du für einen 32-Bit Prozessor, wird int wohl kaum 64-Bit groß sein. Und auf einem 16-Bit System kann sehr wohl der Datentyp long vorhanden sein.

    Die Welt besteht ja nicht nur aus x86 und x64.


Anmelden zum Antworten