ich bin neu in C/C++ (ich beschr�nke mich derzeit auf C++).
Ich bin grunds�tzlich am �berlegen, wie ich Variablen deklarieren sollte,
die numerische Werte enthalten.
Wenn ich mir irgendwelche Beispielcodes durchlese, werden solche Variablen
immer als Integer (int var;) deklariert.
Nun Frage ich mich, ob es nicht grob fahrl�ssig ist, so vorzugehen.
In einem Beispiel habe ich gelesen, wie die Gr��e einer Datei ermittelt
wird, das Ergebnis wird in einer Integer-Variable gespeichert. Das
funktioniert nat�rlich hervorragend bei kleinen Dateien. Aber es gibt eine
Grenze (ich glaube etwa 2 GB?).
Meine Vermutung hat sich best�tigt, als ich die Gr��e einer 7 GB gro�en
Datei ermitteln wollte: Es kam ein unsinniger (negativer) Wert heraus.
Was w�re also die sauberste und beste Vorgehensweise, um in solchen F�llen
(wenn man also Zahlen unbekannter Gr��e bekommt) den gr��ten Datentyp
w�hlt, der existiert?
Ich habe in meinem Fall einfach als long long deklariert (soll angeblich
bis 9223372036854775807 gehen?), dann hat die Sache funktioniert, hier noch
der Code:
long long GetFileSize(string FilePath)
{
long long Out1 = -1;
ifstream file1;
file1.open (FilePath.c_str());
if (file1.is_open())
{
file1.seekg(0, ios::end);
Out1 = file1.tellg();
}
file1.close();
return Out1;
}
> In einem Beispiel habe ich gelesen, wie die Gr��e einer Datei ermittelt
> wird, das Ergebnis wird in einer Integer-Variable gespeichert.
Long, vermutlich?
> Was w�re also die sauberste und beste Vorgehensweise, um in solchen F�llen
> (wenn man also Zahlen unbekannter Gr��e bekommt) den gr��ten Datentyp
> w�hlt, der existiert?
Sauber ist nur eines, n�mlich genau diejenigen Datentypen zu
w�hlen, die in solchen F�llen vorgesehen sind.
(Die Antworten in d.c.l.c werden vermutlich f�r C gegeben,
f�r C++ (eine andere Sprache, trotz historischer
�berlappungen, besonders auch bei den I/O-Klassen vs
den C-Funktionen) wird von woanders Hilfe wahrscheinlicher sein.)
Wenn du die Frage nach Typen f�r Ganzzahl-I/O oder -Nutzung so
allgemein formulierst: Wie soll, ganz technisch, eine zu gro�e Zahl
in eine Variable eines zu kleinen Datentyps gespeichert
werden k�nnen? Geht nicht wirklich.
Wenn die Frage spezieller auf Dateioperationen zielt:
F�r eine gegebene C-Implementierung kann der Datentyp int
2G - 1 nichnegative Werte umfassen. Das muss aber f�r
Dateioperationen nichts hei�en: Denn die C-Funktion
aus der Standard-B�cherei von C wie fseek(3) oder fsetpos(3)
sehen jeweils andere Datentypen f�r Gr��en- bzw. Positionsangaben
vor: zum Beispiel long und fpos_t. Aber fpos_t muss nicht mal
unter der Haube ein Ganzzahltyp sein:
"Although fpos_t has traditionally been an integral type,
applications cannot assume that it is; in particular,
they must not perform arithmetic on objects of this type."
(BSD)
fpos_t hat also nach Definition gar nichts mit int zu tun.
Auch nicht mit long.
"On some non-UNIX systems an fpos_t object may be a complex object
and these routines may be the only way to portably reposition a
text stream." (GNU/Linux)
Demnach ist es nicht gut, wenn �berhaupt m�glich, ein Objekt
wie eine(n) Datei(zeiger) mit Werten zu manipulieren, deren Typ nicht
daf�r vorgesehen ist: int ist nicht f�r Dateioperationen wie
ftell(3) vorgesehen, sondern long; fgetpos(3) bekommt
einen fpos_t.
Wirf das mal deinem compiler zu, vielleicht sagt das Ding was
zu den verwendeten Typen, vielleicht aber auch nicht:
int vorsicht;
vorsicht = ftell(...);
Warum fragst du dann hier?
Hier geht's um C nicht um C++, meine Antworten daher auch f�r C
und nicht f�r C++.
> Ich bin grunds�tzlich am �berlegen, wie ich Variablen deklarieren sollte,
> die numerische Werte enthalten.
> Wenn ich mir irgendwelche Beispielcodes durchlese, werden solche Variablen
> immer als Integer (int var;) deklariert.
> Nun Frage ich mich, ob es nicht grob fahrl�ssig ist, so vorzugehen.
Nein, �berhaupt nicht, man muss nur �ber die Einschr�nkungen
Bescheid wissen. z.b. dass bei int nur ein Wertebereich von
-32767 bis +32767 garantiert ist. Der Wertebereich kann auf manchen
Systemen auch gr��er sein, aber das sind halt die Mindestwerte.
> In einem Beispiel habe ich gelesen, wie die Gr��e einer Datei ermittelt
> wird, das Ergebnis wird in einer Integer-Variable gespeichert. Das
> funktioniert nat�rlich hervorragend bei kleinen Dateien. Aber es gibt eine
> Grenze (ich glaube etwa 2 GB?).
Nein, die liegt schon bei 32767 Byte. s.o.
> Meine Vermutung hat sich best�tigt, als ich die Gr��e einer 7 GB gro�en
> Datei ermitteln wollte: Es kam ein unsinniger (negativer) Wert heraus.
Die Dateigr��e portabel auszulesen ist ohnehin keine triviale Sache,
insofern ist das kein gutes Beispiel. Geht ja schon bei der Frage los
was die Dateigr��e ist. Die Zahl der Bytes die man im Bin�rmodus
lesen kann? Die Zahl der Bytes die man im Textmodus lesen kann?
Die Zahl der Bytes welche die Datei am Speichermedium verbraucht? ...
Du kannst dir ja mal die C-Faq zu dem Thema durchlesen.
> Was w�re also die sauberste und beste Vorgehensweise, um in solchen F�llen
> (wenn man also Zahlen unbekannter Gr��e bekommt) den gr��ten Datentyp
> w�hlt, der existiert?
Der gr��te Datentyp w�re in C intmax_t.
> Ich habe in meinem Fall einfach als long long deklariert (soll angeblich
> bis 9223372036854775807 gehen?),
Ja, das ist der garantierte Mindestbereich. Kann aber auch mehr sein.
Mit unsigned long long kommst sogar garantiert bis 18446744073709551615,
das ist dann auch das gr��te dass du garantiert bekommst.
> dann hat die Sache funktioniert, hier noch
> der Code:
>
> long long GetFileSize(string FilePath)
> {
> long long Out1 = -1;
> ifstream file1;
> file1.open (FilePath.c_str());
> if (file1.is_open())
> {
> file1.seekg(0, ios::end);
> Out1 = file1.tellg();
> }
> file1.close();
>
> return Out1;
> }
Auch wenns C++ ist, warum wechselst du eigentlich den Typ, und nimmst
nicht einfach den Typ den dir tellg liefert? (In dem Fall streampos).
Wenn dir beispielsweise in C die Funktion ftell nur ein long int
zur�ckliefert, hilft es dir genau nix, wenn du das einem long long int
zuweist, dadurch bekommst auch keine Filegr��en jenseits LONG_MAX.
Tom
[...]
> In einem Beispiel habe ich gelesen, wie die Gr��e einer Datei ermittelt
> wird, das Ergebnis wird in einer Integer-Variable gespeichert. Das
> funktioniert nat�rlich hervorragend bei kleinen Dateien. Aber es gibt eine
> Grenze (ich glaube etwa 2 GB?).
> Meine Vermutung hat sich best�tigt, als ich die Gr��e einer 7 GB gro�en
> Datei ermitteln wollte: Es kam ein unsinniger (negativer) Wert
> heraus.
'Groesse einer Datei' ist kein durch die C-Norm definierter Begriff
und die Antwort auf diese Frage ist plattformspezifisch. Fuer UNIX(*)
lautet sie off_t.
[...]
> Was w�re also die sauberste und beste Vorgehensweise, um in solchen F�llen
> (wenn man also Zahlen unbekannter Gr��e bekommt) den gr��ten Datentyp
> w�hlt, der existiert?
'Zahlen unbekannter Groesse' kann mit elementaren Datentypen der
Sprache C nicht handhaben, da diese alle einen maximalen Wertbereich
haben.
Sei froh, unter DOS w锟絩e die Grenze bei 32k :-)
> Meine Vermutung hat sich best锟絫igt, als ich die Gr锟斤拷e einer 7 GB gro锟絜n
> Datei ermitteln wollte: Es kam ein unsinniger (negativer) Wert heraus.
>
> Was w锟絩e also die sauberste und beste Vorgehensweise, um in solchen F锟絣len
> (wenn man also Zahlen unbekannter Gr锟斤拷e bekommt) den gr锟斤拷ten Datentyp
> w锟絟lt, der existiert?
Man w锟絟lt die zum API passenden Typen. C's <stdio.h> hat zum einen
ftell/fseek, die als Parameter 'long' nehmen. Damit kommst du auf heute
锟絙lichen Systemen bis 2 GByte. Klar, ist 'ne Einschr锟絥kung, aber es ist
nicht wirklich sinnvoll, als Nutzer dieser Funktionen dann einen anderen
Typen zu nutzen.
Au锟絜rdem gibt es fgetpos/fsetpos mit 'fpos_t', mit denen du dir zwar
Positionen in beliebig gro锟絜n Dateien merken kannst, wo du aber sonst
portabel nicht allzuviel mit machen kannst.
> Ich habe in meinem Fall einfach als long long deklariert (soll angeblich
> bis 9223372036854775807 gehen?),
'long long' geht mindestens bis 2**63-1.
> dann hat die Sache funktioniert, hier noch der Code:
>
> long long GetFileSize(string FilePath)
> {
> long long Out1 = -1;
> ifstream file1;
> file1.open (FilePath.c_str());
> if (file1.is_open())
> {
> file1.seekg(0, ios::end);
> Out1 = file1.tellg();
Abgesehen davon, dass C++ nach nebenan geh锟絩t: in C++ lautet der Typ f锟絩
die Stream-Position 'istream::pos_type'. Ob und in welchen ganzzahligen
Typ man den portabel wandeln darf, ist im Sprachstandard so gut
versteckt, dass ich es jetzt nicht finde.
Stefan
> Dominik Schmidt schrieb:
>
>> In einem Beispiel habe ich gelesen, wie die Gr��e einer Datei ermittelt
>> wird, das Ergebnis wird in einer Integer-Variable gespeichert.
>
> Long, vermutlich?
Ja, ich meinte Long.
> Sauber ist nur eines, n�mlich genau diejenigen Datentypen zu
> w�hlen, die in solchen F�llen vorgesehen sind.
>
> (Die Antworten in d.c.l.c werden vermutlich f�r C gegeben,
> f�r C++ (eine andere Sprache, trotz historischer
> �berlappungen, besonders auch bei den I/O-Klassen vs
> den C-Funktionen) wird von woanders Hilfe wahrscheinlicher sein.)
Also auf Deutsch: Ich bin in der falschen NG, richtig?
Vermutlich w�re de.comp.lang.iso-c++ besser, nehme ich an?
> Wenn du die Frage nach Typen f�r Ganzzahl-I/O oder -Nutzung so
> allgemein formulierst: Wie soll, ganz technisch, eine zu gro�e Zahl
> in eine Variable eines zu kleinen Datentyps gespeichert
> werden k�nnen? Geht nicht wirklich.
Nein, sicher, alles hat seine Grenzen.
Aber Dateien k�nnen eben gr��er als 2 GB sein. In einem solchen Fall kann
ich doch die Dateigr��e nicht in einer Long-Variable speichern (hat ja auch
nicht funktioniert)?
Float ist auch ungeeignet, da eine exakte (positive) Ganzzahl herauskommen
soll.
Und wenn die maximale Gr��e einer Long Long Variable tats�chlich bei
9223372036854775807 liegt (8 Exabyte?), w�re dieser Datentyp doch eher
geeignet, da ich davon ausgehe, dass mein Programm niemals mit einer solch
gro�en Datei umgehen muss (sondern immer mit kleineren)?
error: invalid conversion from `void*' to `FILE*'|
Passt das denn in meine Funktion?
Bitte hab Verst�ndnis, bin eben noch ein wenig neu (vorher fast nur VB6)...
Ja
> Vermutlich w�re de.comp.lang.iso-c++ besser, nehme ich an?
Nochmal ja.
>> Wenn du die Frage nach Typen f�r Ganzzahl-I/O oder -Nutzung so
>> allgemein formulierst: Wie soll, ganz technisch, eine zu gro�e Zahl
>> in eine Variable eines zu kleinen Datentyps gespeichert
>> werden k�nnen? Geht nicht wirklich.
>
> Nein, sicher, alles hat seine Grenzen.
> Aber Dateien k�nnen eben gr��er als 2 GB sein. In einem solchen Fall kann
> ich doch die Dateigr��e nicht in einer Long-Variable speichern (hat ja auch
> nicht funktioniert)?
Klar. Allerdings gibts Systeme wo es gar keine Dateien gr��er als 2GB
gibt.
> Float ist auch ungeeignet, da eine exakte (positive) Ganzzahl herauskommen
> soll.
> Und wenn die maximale Gr��e einer Long Long Variable tats�chlich bei
> 9223372036854775807 liegt (8 Exabyte?), w�re dieser Datentyp doch eher
> geeignet, da ich davon ausgehe, dass mein Programm niemals mit einer solch
> gro�en Datei umgehen muss (sondern immer mit kleineren)?
Das Spiel kannst auch mit long und Files < 2GB spielen. :-)
Wie schon gesagt, warum willst du unbedingt long long nehmen, und
nicht einfach den daf�r vorgesehenen Datentyp? (Welcher das genau
ist, h�ngt von der Methode ab, mit der du die Filegr�sse ermitteln
willst).
>> Wirf das mal deinem compiler zu, vielleicht sagt das Ding was
>> zu den verwendeten Typen, vielleicht aber auch nicht:
>>
>> int vorsicht;
>>
>> vorsicht = ftell(...);
>
> error: invalid conversion from `void*' to `FILE*'|
Was �bergibst du denn an ftell? Die Meldung klingt danach, dass es
kein Filepointer ist, der von fopen zur�ckgeliefert wurde. Dann
kann das nat�rlich nicht funktionieren.
> Passt das denn in meine Funktion?
Was meinst du damit?
Tom
> ich bin neu in C/C++ (ich beschr�nke mich derzeit auf C++).
Dann bist Du hier falsch. Hier geht es nur um C, nicht um C++.
Versuch's mal nebenan in de.comp.lang.iso-c++.
Gru�. Claus
Du meinst bei 16 Bit ints.
Aber selbst unter DOS war man schlau genug die Datei-Pointer als 32 Bit
auszulegen.
> Au�erdem gibt es fgetpos/fsetpos mit 'fpos_t', mit denen du dir zwar
> Positionen in beliebig gro�en Dateien merken kannst, wo du aber sonst
> portabel nicht allzuviel mit machen kannst.
Viele APIs bieten zus�tzliche Funktionen mit '64' hinten, um korrekt mit
gr��eren Files umzugehen.
> Abgesehen davon, dass C++ nach nebenan geh�rt: in C++ lautet der Typ f�r
> die Stream-Position 'istream::pos_type'.
Traurigerweise ist die iostream-Library oft die letzte, die auf 64 Bit
portiert wird und m.E. auch eines der eher dunklen und veralteten
Kapitel von C++.
Marcel
> Du meinst bei 16 Bit ints.
Ja, das d�rfte die Breite eines int bei den meisten DOS-Compilern
gewesen sein.
> Aber selbst unter DOS war man schlau genug die Datei-Pointer als 32 Bit
> auszulegen.
Der OP hat ja explizit von "int" geschrieben. Es hilft dir nix wenn
du vom Datei-Pointer einen 32 Bit Wert (in dem Fall long) bekommst
und das Ergebnis dann einer 16 Bit Variablen (int) zuweist.
Auch wenn auf heutigen Systemen oft gilt sizeof(int) == sizeof(long),
das ist keine C-Garantie. Gerade bei Unix- oder Windowsprogrammen
sieht man aber immer wieder ein verlassen auf diese nicht garantierte
Annahme.
>> Au�erdem gibt es fgetpos/fsetpos mit 'fpos_t', mit denen du dir zwar
>> Positionen in beliebig gro�en Dateien merken kannst, wo du aber sonst
>> portabel nicht allzuviel mit machen kannst.
>
> Viele APIs bieten zus�tzliche Funktionen mit '64' hinten, um korrekt mit
> gr��eren Files umzugehen.
>> Abgesehen davon, dass C++ nach nebenan geh�rt: in C++ lautet der Typ f�r
>> die Stream-Position 'istream::pos_type'.
>
> Traurigerweise ist die iostream-Library oft die letzte, die auf 64 Bit
> portiert wird und m.E. auch eines der eher dunklen und veralteten
> Kapitel von C++.
Wobei der OP in der gl�cklichen Lage zu sein scheint, eine
Implementierung erwischt zu haben die es "richtig" macht.
Tom
Aus Betriebssystemsicht sind Dateien nicht notwendigerweise
unstrukturierte Byte-Folgen und konsequenterweise gibt es ein Konzept
'Groesse einer Datei', repraesentierbar durch eine positive, ganze
Zahl, die die Anzahl der enthaltenen Bytes angibt, in C nicht.
Öhm... also, DJGPP benutzt IIRC 32 Bit dafür. Aber DJGPP ist ja auch ein
Sonderfall.
> Auch wenn auf heutigen Systemen oft gilt sizeof(int) == sizeof(long),
> das ist keine C-Garantie. Gerade bei Unix- oder Windowsprogrammen
> sieht man aber immer wieder ein verlassen auf diese nicht garantierte
> Annahme.
>
Das ist dann übrigens die Software, die am Sprung auf 64-bit-Prozessoren
scheitert: Wenigstens das System V ABI for AMD64 spezifiziert als
Programmiermodell LP64 (d.h. sizeof(int) == 4, sizeof(long) ==
sizeof(void*) == 8).
Übrigens gibt es auch Software, die unter der Annahme
sizeof(int)==sizeof(void*) läuft :-)
>> Viele APIs bieten zusätzliche Funktionen mit '64' hinten, um korrekt mit
>> größeren Files umzugehen.
Wieso die nicht gleich die return types umdefinieren können? Wegen der
Binär-Kompatibilität?
HTH,
Markus
--
Nur weil ein Genie nix reißt, muß ja nun nicht gleich jeder Idiot
pausieren... Bully hats ja auch geschafft.
-- gUnter nanonüm in de.alt.anime