size_t und das Dateisystem



  • Ich wollte mich mal schlau machen warum es von Vorteil ist size_t zu benutzen. Bisher habe ich herausgefunden das size_t zB verwendet wird um die Größe von Dateien in Bytes zu speichern. Als ich Wissen wollte wie Groß size_t sein kann, habe ich gelesen das size_t eigentlich unsigned int ist, aber es kommt auf das Dateisystem an wieviel size_t speichern kann. Ist das korrekt?

    Das würde heißen size_t kann auf ext4 Dateisystemen eine 16 Terabyte große Datei in Bytes speichern oder irre ich mich da?



  • std::size_t is the unsigned integer type of the result of the sizeof operator as well as the sizeof... operator and the alignof operator (since C++11).

    Ich kann da nichts im Zusammenhang mit Dateigrößen erkennen.



  • Bennisen schrieb:

    aber es kommt auf das Dateisystem an wieviel size_t speichern kann. Ist das korrekt?

    Das ist unmöglich, ein kompiliertes Programm ist ein kompiliertes Programm, wenn es unter Debian läuft (z.B.) dann ändert sich das programm (Die Datentypen) nicht einfach so wenn du nun ext3 oder ext4 oder sogar beides nutzt.



  • Hab jetzt anscheinend herausgefunden was die maximale Größe von size_t sein kann mit std::numeric_limitsstd::size_t::max(). Wenn ich mir das ausgeben lasse kommt folgende Zahl dabei raus 18 446 744 073 709 551 615. Das ist deutlich mehr als ich gedacht habe und den englischen Beitrag den ich gelesen habe war total falsch.

    Aber wie kommt die Größe zustande?



  • sorry doppelpost



  • Mach mal log2(Deine Zahl + 1) davon!



  • decimad schrieb:

    Mach mal log2(Deine Zahl + 1) davon!

    4294967296 kommt dabei raus. Die Zahl kommt mir bekannt vor. Bei meiner Recherche ist das irgendwo schonmal aufgetaucht. Das wäre eine Größe von ca. 4,3 Gigabyte. Ist das dann die maximale Größe in Bytes die size_t enthalten kann?

    Was war denn das für ein Wert den ich da rausbekommen habe durch die gepostete Funktion?

    Bin noch ein totaler Grünschnabel und nicht unbedingt ein Genie in Informatik, würde das gerne aber verstehen. Da es momentan für ein kleines Projekt relevant wäre.



  • 2^64 = 18.446.744.073.709.551.616
    2^32 = 4.294.967.296

    Bei MS VS 2015 in vcruntime.h:

    // Definitions of common types
    #ifdef _WIN64
        typedef unsigned __int64 size_t;
        typedef __int64          ptrdiff_t;
        typedef __int64          intptr_t;
    #else
        typedef unsigned int     size_t;
        typedef int              ptrdiff_t;
        typedef int              intptr_t;
    #endif
    

    Code::Blocks / gcc:
    stddef.h:

    #define __SIZE_TYPE__ long unsigned int
    typedef __SIZE_TYPE__ 	size_t;
    


  • Och, Junge, ernsthaft?

    https://en.wikipedia.org/wiki/C_data_types#stddef.h schrieb:

    size_t is an unsigned integral type used to represent the size of any object (including arrays) in the particular implementation. The sizeof operator yields a value of the type size_t. The maximum size of size_t is provided via SIZE_MAX, a macro constant which is defined in the <stdint.h> header (cstdint header in C++). size_t is guaranteed to be at least 16 bits wide. Additionally, POSIX includes ssize_t, which is a signed integral type of the same width as size_t.

    Als Faustregel kannst du dir merken: size_t ist so groß, dass es jeden Wert, den ein sizeof auf ein Array zurückgeben kann, halten kann.

    Jetzt kommt mein gefährliches Halbwissen dazu - aber nur, weil ich noch nicht auf Systemen mit segmentiertem Speicher programmiert habe. Aber soweit ich weiß, hast du auf genau diesen Systemen das Problem, dass ein Array nicht größer sein kann als das Segment, in dem es angelegt wird. Ein size_t ist auf diese Segmentgrößen limitiert, deine Speicheranforderungen sind es mitunter nicht.. Und dann bieten sich Typen wie unitptr_t an.

    ABER: wenn man auf dem eigenen Rechner, der ein x86 oder x64 ist, programmiert, stehen die Chancen nicht schlecht, dass sizeof(uintptr_t) == sizeof(size_t). Deswegen erkennst du nicht sofort den Unterschied. Und ein uintptr_t soll groß genug sein, um jeden Pointer ans Ganzzahl halten zu können. Nicht, dass Pointer nicht eh schon Ganzzahlen sind ... aber in der Hinsicht sind auf einigen Systemen size_t und uintptr_t sich gleich und gehen bis 2^64 - 1.



  • Erhard Henkes schrieb:

    2^64 = 18.446.744.073.709.551.616
    2^32 = 4.294.967.296

    Bei MS VS 2015 in vcruntime.h:

    // Definitions of common types
    #ifdef _WIN64
        typedef unsigned __int64 size_t;
        typedef __int64          ptrdiff_t;
        typedef __int64          intptr_t;
    #else
        typedef unsigned int     size_t;
        typedef int              ptrdiff_t;
        typedef int              intptr_t;
    #endif
    

    Also gibt es da einen Unterschied bei 32 und 64bit Systemen?



  • Bennisen schrieb:

    Also gibt es da einen Unterschied bei 32 und 64bit Systemen?

    Yup.

    Und noch was: genau deswegen solltest du immer size_t oder uintptr_t bei Größen verwenden. Auf keinen Fall unsigned int oder dergleichen. size_t garantiert dir, dass es groß genug ist, um Längen zu halten - dass es auf 64-Bit-Systemen ohne Segmentierung 8 Byte groß ist. Auf Windows ist ein unsigned int aber 32 Bit. Deswegen merke: immer size_t/uintptr_t verwenden, und keine eigenen Typen erfinden. 😉



  • dachschaden schrieb:

    Bennisen schrieb:

    Also gibt es da einen Unterschied bei 32 und 64bit Systemen?

    Yup.

    Und noch was: genau deswegen solltest du immer size_t oder uintptr_t bei Größen verwenden. Auf keinen Fall unsigned int oder dergleichen. size_t garantiert dir, dass es groß genug ist, um Längen zu halten - dass es auf 64-Bit-Systemen ohne Segmentierung 8 Byte groß ist. Auf Windows ist ein unsigned int aber 32 Bit. Deswegen merke: immer size_t/uintptr_t verwenden, und keine eigenen Typen erfinden. 😉

    Ok danke für den Tipp.

    Aber was wäre denn wenn ich, bei 32bit, die Größen von 4 Dateien, die jeweils 5 GByte groß sind, als gesamte Größe in size_t speichern möchte?



  • #include <iostream>
    #include <cstdint>
    
    int main()
    {
    	uint8_t a = 42 ;
    	uint16_t b = 42;
    	uint32_t c = 42;
    	uint64_t d = 42;
    	size_t e = 42;
    	int f = 42;
    
    	std::cout << sizeof(a) << " " << sizeof(b) << " " << sizeof(c) << " " << sizeof(d) << " " << sizeof(e) << " " << sizeof(f) << std::endl;
    }
    

    x86: 1 2 4 8 4 4
    x64: 1 2 4 8 8 4

    Hier sieht man den Vorteil von size_t bei einer Migration von 32 nach 64 bit bei der Kompilierung. Die normalen Typen bleiben allerdings gleich, übrigens auch int. Beides hat seine Vor-/Nachteile.



  • Bennisen schrieb:

    Ok danke für den Tipp.

    Aber was wäre denn wenn ich, bei 32bit, die Größen von 4 Dateien, die jeweils 5 GByte groß sind, als gesamte Größe in size_t speichern möchte?

    Windows hat dafür einen speziellen API-Call, GetFileSizeEx. Die Funktion übernimmt einen Zeiger auf einen LARGE_INTEGER, der 64 Bit groß ist.

    Unter POSIX-Systemen wird off_t verwendet. Allerdings nicht direkt - meist wird direkt stat genommen. Gibt's auch unter Windows als _stat , aber meines Wissens ist das nicht mehr direkte, nakte API.

    Und der Hirnriss bei beiden Typen ist, dass die signed sind ... und 64 Bit. Aber dennoch signed.

    EDIT: Übrigens: wenn du versuchst, einem 32-Bit-Speicherbereich mehr zuzuweisen, als er halten kann, wird der Bereich, den er nicht halten kann, abgeschnitten. Und das ist der Vater aller Sicherheitslücken - ich will 0x1 0000 0001 Elemente haben, der dumme Programmierer speichert das aber in einem 32 Bit-Wert, der große Teil wird abgeschnitten, malloc/new bekommt nur was von einem Element mit, und dann kann ich schön in den Heap schreiben.



  • also könnt ihr mir empfehlen off_t zu verwenden, wenn ich die Größe von Dateien erfassen oder zusammenfassen möchte?
    Hab es gerade mal im Code eingebaut. Funktioniert momentan ohne Probleme.



  • Ich würde eher streamoff empfehlen. Das ist immerhin im Standard und dürfte über Überwege dem Typ entsprechen den tellg/tellp/seekg/seekp nutzen. Oder wenn du den Typ gar nicht selbst genau wissen musst einfach auto benutzen.



  • Wenn es Dir nicht um besondere Funktionalitäten geht, sondern lediglich um die Dateigröße in Byte, dann kannst Du einfach uint64_t verwenden. Damit kannst Du bis 2^64 - 1 Byte speichern. Größere Filegrößen könntest Du als KB oder MB abspeichern, oder wenn es ganz exakt in Byte sein muss, dann mit BigInteger-Klassen. ich verwende für so etwas z.B. eine reduzierte BigUnsigned-Klasse: http://henkessoft.de/Sonstiges/MyBigUnsigned.rar



  • Vielen Dank ich werde mir das mal alles anschauen.

    Noch eine Offtopic Frage...

    Ich bin jetzt ein normaler User und hatte bisher Server mit Dateien die nicht größer als ca. 1GByte waren. Gibt es in größeren Infrastrukturen auch Dateien die "um einiges" größer werden als ein paar GByte?



  • Erhard Henkes schrieb:

    Damit kannst Du bis 2^64 - 1 Byte speichern. Größere Filegrößen [...]

    Naja mit 64 Bit kann man schon Dateigrößen darstellen die bis 18 Mio. TB gehen. Bis wir dort sind wird es wohl noch ein Weilchen dauern. Und damit kommen wir auch schon zur OT Frage. Wie definierst du "um einiges"? Ich habe schon 50GB Dateien mit meinen C++ Programmen produziert und weiter verarbeitet. Und das ist ja auch noch nichtmal groß. Festplatten mit 1TB und mehr gibts an jeder Straßenecke. Mit größeren Speichersystemen kriegt man auch einige 100 TB Speicherplatz aber mich wurde schon wundern wenn dort wirklich nur eine große Datei drauf liegt. Prinzipiell arbeitet man mit diesen Dateien aber auch nicht anders als mit kleineren Dateien. Gut man kann sich schonmal nicht alles in den RAM kopieren, höchstens Ausschnitte.



  • da ich eh boost verwende, habe ich jetzt uintmax_t dafür benutzt. Problem gelöst. Danke nochmal.


Log in to reply