int oder size_t



  • Hallo Zusammen,

    nach einiger Zeit des Lesens hier im Forum ist mir mehrfach die Deklaration size_t als Datentyp für die Länge von Speicherbereichen aufgefallen.

    Etwas suchen ergab, size_t ist nach dem ANSI-C Standard wie folgt definiert:

    typedef unsigned long size_t;
    

    Bisher habe ich für Längen von Speicherbereichen immer nur normale int oder unsigned int genommen. Gehe ich nun richtig der Annahme, dass dann mein Code nicht dem Standard entspricht und ich dafür eher den Typ size_t verwenden sollte?


  • Mod

    Da Speichermengen niemals negativ sein können, gleichzeitig aber leicht größer sein können als INT_MAX, liegt es schon nahe, size_t dafür zu benutzen.

    int zu benutzen ist aber kein "echter" Fehler in deinem Programm. Bloß eine Designschwäche, da dein Programm dann mit manchen speicherintensiven Szenarien nicht mehr zurecht kommt, die mit size_t kein Problem wären.



  • Vielen Dank für die Antwort.

    Gibt es denn eine Möglichkeit meinen Code auf einen gewissen Standard zu prüfen bzw. eine Art Auflistung, wie ich was in den verschiedenen Standards gestalten kann? (Ohne die Auflistung sämtlicher Standardfunktionen manuell durchzugehen) Bisher habe ich mich entsprechend dem Galileo Openbook am C99-Standard orientiert. Zwecks Portabilität sei der ANSI-Standard wohl besser, weswegen ich gerne auf diesen wechseln würde.

    Ich entwickel unter Gentoo mit dem GCC-4.x. Recherchen ergaben mittels den Flags -std=c89 und -pedantic-errors kann der GCC bereits nach diesem Standard prüfen und entsprechende Ausgaben machen.



  • Nirvash schrieb:

    Etwas suchen ergab, size_t ist nach dem ANSI-C Standard wie folgt definiert:

    typedef unsigned long size_t;
    

    Das ist falsch.
    size_t ist vom Standard als ein vorzeichenloser Integertyp vorgegeben, die konkrete Definition ist implementierungsabhängig.
    Auch ist size_t kein Basistyp wie int, sondern muss via #include bekanntgemacht werden.
    Und die Vorzeichenlosigkeit bedingt auch eine gewisse Sorgfalt,

    strlen("")-strlen("1");
    

    ist wegen size_t als Rückgabetyp von strlen etwas fragil.



  • Nirvash schrieb:

    Gibt es denn eine Möglichkeit meinen Code auf einen gewissen Standard zu prüfen

    gcc -Wall -ansi -pedantic *.c  /* für C89 Konformität */
    bzw.
    gcc -Wall -std=c99 -pedantic *.c  /* für C99 Konformität */
    

    Nirvash schrieb:

    Bisher habe ich mich entsprechend dem Galileo Openbook am C99-Standard orientiert.

    Oh Gott, Pfuscher JW und Standard-Konformität schließen sich gegenseitig aus.



  • int wird im Standard schön beschrieben als

    A ‘‘plain’’ int object has the natural size suggested by the architecture of the execution environment[...]

    Daraus folgt für mich: Wenn irgendwie garantiert ist, dass ich mich im Wertebereich eines int bewege: nehme ich auch einen. Warum soll ich gegen die Architektur arbeiten?
    Manchmal sieht man hier "überkorrekten" code wie

    for(size_t i=0; i<8; ++i)...
    

    . Das ist - meiner bescheidenen Meinung nach - Quark.



  • Wutz schrieb:

    Oh Gott, Pfuscher JW und Standard-Konformität schließen sich gegenseitig aus.

    Kann ich daraus schließen, das Openbook ist nicht von guter Qualität?





  • Wutz schrieb:

    Auch ist size_t kein Basistyp wie int, sondern muss via #include bekanntgemacht werden.

    wo ist size_t definiert? in stdint.h?


  • Mod

    Furble Wurble schrieb:

    Wenn irgendwie garantiert ist, dass ich mich im Wertebereich eines int bewege: nehme ich auch einen.

    Das ist auch richtig so, aber beim hier beschriebenen

    für die Länge von Speicherbereichen

    ist man eben gerade nicht im Wertebereich eines int.

    wo definiert? schrieb:

    wo ist size_t definiert? in stdint.h?

    Ich helf dir mal, dir selbst zu helfen:
    www.google.com
    www.cplusplus.com



  • size_t definiert in stddef.h



  • "int oder size_t"?

    Kommt drauf an.

    die c-Standardlib verwendet für integer-rückgabewerte stets "size_t".

    ergo: wenn das ganze irgendwie etwas plattformübergreifend sein soll und du eine lib programmierst, dann solltest du vielleicht size_t verwenden.

    was mir dabei nicht so klar ist: viele funktionen verwenden size_t variablen auch für malloc.

    mal folgendes gedankenbeispiel:
    auf meinem system ist size_t als unsigned short definiert, ist also 2 bytes groß.
    damit ist der maximalwert: 0xFFFF ( = 65535 )

    nun will ein quelltext mit malloc speicher reservieren.
    das könnte so aussehen:

    size_t var1=0xFFFFFFFF;
    void *pointer=malloc(var1);
    

    das problem ist: mein size_t kann den var1-wert garnicht aufnehmen, weil der MAX wert überschritten wird (0xFFFFFFFF > 0xFFFF).

    hier würde wahrscheinlich der compiler warnen, und wahrscheinlich würde am ende das programm abstürzen, und dass nur, weil die bytegröße von size_t nicht genau definiert ist.

    würde das programm statt size_t uint32_t benutzen, wäre alles ok.

    was sagt ihr?



  • SeppJ schrieb:

    Furble Wurble schrieb:

    Wenn irgendwie garantiert ist, dass ich mich im Wertebereich eines int bewege: nehme ich auch einen.

    Das ist auch richtig so, aber beim hier beschriebenen

    für die Länge von Speicherbereichen

    ist man eben gerade nicht im Wertebereich eines int.

    Nicht im Allgemeinen, nein, deswegen z.B. an Schnittstellen size_t.

    Aber im Speziellen kann auch

    die Länge von Speicherbereichen

    kleiner als 32Tsd. u. ein paar zerquetschte sein.

    char buf[32];
    

    warum soll ich hier nicht int als index in buf nehmen?


  • Mod

    ein problem wäre da... schrieb:

    auf meinem system ist size_t als unsigned short definiert, ist also 2 bytes groß.
    damit ist der maximalwert: 0xFFFF ( = 65535 )

    Dann kann auf diesem System kein einzelnes Objekt größer als 64kB (-1) sein. Folglich ist auch keine dynamische Allokation über einen größeren Bereich per malloc unmöglich, denn malloc gibt zusammenhängenden Speicher zurück (der folglich u.a. als einzelnes char-Array, also ein Objekt angesehen werden kann). DOS ist ein schönes Beispiel, bei dem man size_t als 16-bit hätte definieren können (praktisch nicht, schon weil das lange vor der Standardiesierung existierte und size_t bekanntlich noch für andere Zwecke missbraucht wurde)..
    Das Beispiel verstehe ich nicht.

    size_t var1=0xFFFFFFFF;
    

    Initialisiert var1 mit 0xFFFF. Typischerweise wird ein Compiler dabei warnen.

    void *pointer=malloc(var1);
    

    Fordert folglich einen Speicherblock der Größe 64kB-1 an (was praktisch nicht erfolgreich sein würde, weil der größte anforderbare Speicherblock typischerweise kleiner ist als die maximale theoretische Größe wegen des Verwaltungsaufwandes).



  • camper schrieb:

    ein problem wäre da... schrieb:

    auf meinem system ist size_t als unsigned short definiert, ist also 2 bytes groß.
    damit ist der maximalwert: 0xFFFF ( = 65535 )

    Dann kann auf diesem System kein einzelnes Objekt größer als 64kB (-1) sein. Folglich ist auch keine dynamische Allokation über einen größeren Bereich per malloc unmöglich, denn malloc gibt zusammenhängenden Speicher zurück (der folglich u.a. als einzelnes char-Array, also ein Objekt angesehen werden kann). DOS ist ein schönes Beispiel, bei dem man size_t als 16-bit hätte definieren können.
    Das Beispiel verstehe ich nicht.

    gut, das gleiche beispiel mit anderen werten:
    sizeof(size_t) = 4

    size_t var1=0xFFFFFFFFFFFFFFFF; // 8 bytes
    void *pointer=malloc(var1);
    

    ich weiß, das 0x... ein unheimliche große zahl wäre. aber nehmen wir mal an, ich hätte so viel arbeitsspeicher.


  • Mod

    ein problem wäre da... schrieb:

    würde das programm statt size_t uint32_t benutzen, wäre alles ok.

    was sagt ihr?

    Gequirlter Unsinn. Der size_t auf dem beschriebenen System ist doch unsinged short, weil unsigned short den großtmöglichen, theoretisch vorstellbaren Speicherbereich auf diesem System beschreibt. Das ist eine technische Grenze. Die ändert sich auch nicht, wenn du einen anderen Datentyp benutzt. Das wäre ja so als ob man durch

    #undef INT_MAX
    #define INT_MAX 123
    

    die Größe eines int verändern könnte.
    edit:

    anderes beispiel schrieb:

    gut, das gleiche beispiel mit anderen werten:

    Und? Das ist das gleiche Beispiel mit anderen Werten. Das ändert nichts an der Antwort, die du nun 2x bekommen hast.

    Furble Wurble schrieb:

    char buf[32];
    

    warum soll ich hier nicht int als index in buf nehmen?

    Verbietet dir doch niemand. Zumindest wenn du ganz sicher bist, dass das für alle Zeiten 32 bleibt, weil hier die 32 keine Speichermenge beschreibt, sondern weil sie für irgendeine fundamentale Größe in deinem Algorithmus steht (ein Beispiel wäre double vec[3]; für ein Programm, das mit 3D-vektoren arbeitet). Wenn die 32 jedoch eine beliebige Speichermenge sein könnte, dann nimm bitte size_t.

    Z.B.

    int laenge = strlen(nutzereingabe);
    

    Bei so etwas wäre size_t richtig. Oder

    void funktion_auf_array(Typ array[], int length);
    

    Auch.



  • SeppJ schrieb:

    eine beliebige Speichermenge sein könnte, dann nimm bitte size_t.

    Danke, dass beantwortet meine Frage 🙂

    Für die nähere Lektüre bezüglich C habe ich mich jetzt in Anlehnung an einer Empfehlung aus dem Forum für dieses Werk entschieden: The C Programming Language. (Prentice Hall Software).
    Mein Ziel ist es C nicht nur zu lernen, sondern die Sprache auch zu verstehen und sauberen sowie vernünftigen Code zu produzieren.



  • SeppJ schrieb:

    Furble Wurble schrieb:

    char buf[32];
    

    warum soll ich hier nicht int als index in buf nehmen?

    Verbietet dir doch niemand. Zumindest wenn du ganz sicher bist, dass das für alle Zeiten 32 bleibt, weil hier die 32 keine Speichermenge beschreibt, sondern weil sie für irgendeine fundamentale Größe in deinem Algorithmus steht (ein Beispiel wäre double vec[3]; für ein Programm, das mit 3D-vektoren arbeitet). Wenn die 32 jedoch eine beliebige Speichermenge sein könnte, dann nimm bitte size_t.

    Z.B.

    int laenge = strlen(nutzereingabe);
    

    Bei so etwas wäre size_t richtig. Oder

    void funktion_auf_array(Typ array[], int length);
    

    Auch.

    Keine Diskussion. S.o.

    Furble Wurble schrieb:

    deswegen z.B. an Schnittstellen size_t.

    Allerdings gibt es auch noch ganz schlaue, die bei z.B. 32 Elementen im Array sagen: "Nehm ich doch char, das reicht auch Dicke als Index!"
    Das ist genauso "unnatürlich" wie size_t.


  • Mod

    Furble Wurble schrieb:

    Das ist genauso "unnatürlich" wie size_t.

    size_t ist keine unnatürliche Größe im Computer. Die maximale Speichermenge ist ja oftmals gegeben durch eben den Maximalwert des natürlichen Datentyps.

    Nirvash schrieb:

    Für die nähere Lektüre bezüglich C habe ich mich jetzt in Anlehnung an einer Empfehlung aus dem Forum für dieses Werk entschieden: The C Programming Language. (Prentice Hall Software).
    Mein Ziel ist es C nicht nur zu lernen, sondern die Sprache auch zu verstehen und sauberen sowie vernünftigen Code zu produzieren.

    Da ist das Buch sicher eine gute Wahl 👍 . Leider nicht 100% fehlerfrei (aber nur Kleinigkeiten) oder aktuell, aber sehr gut was das Verstehen der Sprache angeht.



  • also sollte man, wenn man libs programmiert, und eine integervariable braucht, grundsätzlich mit "size_t" arbeiten?


Anmelden zum Antworten