Fragensteller
fscanf, fgetchar und ifstream Problem beim lesen einer Textdatei

Frage
-
Hallo,
Ich bin mit meinem Latein langsam am Ende. Ich habe ein älteres, großes VC++ 6.0
Projekt zu betreuen und dieses verwendet fscanf um Textdateien auszulesen.
Das dumme ist nur, das in der Buffervariable char[80] = {\0} definitiv nichts
ankommt.Das selbe passiert wenn ich alternativ fgetchar oder ifstream nutze.
Die Textdatei: c:\testo.txt (codepfad ist c:\\texto.txt ist definitiv vorhanden und
wird auch z.B von fopen korrekt geöffnet. Ändere ich den Dateinamen gibts auch
eine Fehlermeldung und ifstream sagt ebenfalls das die Datei geöffnet ist.Der Knackpunkt ist einfach das weder fscanf noch fgetchar noch ifstream
in der lage sind irgend etwas aus der Textdatei auszulesen (nur in dem
alten VC 6.0 C/C++ Riesenprojekt. Komischerweise funktioniert der selbe
Code aber in isolierter form in einem neu erstellten dummy Exe Projekt.Der Code funktioniert unmigriert unter VS2003 ohne Probleme.
Was ich bisher versucht habe.1)
Neues Exe Projet erstellt und nach und nach alle Sourcefiles, Resources und
Header sowie Libs eingebaut (um sicher zu gehen das mir der Conversion Wizzard
bei der Migration von VC 6 C++ auf VC2010 nicht kaputt gemacht hat.Ergebnis: leider negativ.
2)
Das Projekt und die Codestelle befindet sich in einer Static Lib, also habe ich den
Code isoliert und in die WinMain Funktion gepackt.Ergebnis: Ebenfalls negativ.
3)
Ich arbeite unter Vista mit VS2010 SP1 + WinSDK 7.1 und als Platform Toolset
ist Windows SDK 7.1 eingestellt. Ich habe beide Toolsets VC builtin und SDK 7.1
getestet. Funktioniert für meine Dummy Exe, aber nicht im Hauptprojekt das migriert
wurde.Ergebnis: Ebenfalls negativ.
4)
Das Problem tritt in Win32 32-Bit Debug und Release Konfiguration auf. Ich habe
Versucht Manifest Einstellungen zu ändern bzw UAC abzuschalten aber als das nichts
half habe ich es zurück gesetzt.5)
Da ich das Intell Parallel Studio 13 installiert habe und mir der Intel 32 als
auch der 64-Bit x86 Compiler zur verfügung steht, habe ich mal testweise das
Projekt auf kompilation mit dem Intel Compiler ungestellt. Der Code läuft
erheblich schneller, nur leider ist der Fehler der gleiche (obwohl Compiler, Linker
und *.libs völlig andere als der MS Visual C/C++ Compiler.6)
Ich habe WinDBG und AppVerifier (32-Bit) laufen lassen, es kommt zu keiner
Exception oder dergleichen. Alle Symbols sind aufgelöst nur an der Stelle wo
halt fscanf, fgetchar oder istream zuschlägt kommen einfach keine Zeichen.Fazit:
Das Programm läuft, aber ab dem Punkt wo fscanf oder fgetcgar oder ifstreamzuschlägt kommen schlicht und ergreifend keine Zeichen zurück. Es sind einfach blanks "". Ich habe
die entsprechenden Variablen in die Watchlist gepackt, Symbolserver eingerichtetund ich kann den Code schrittweise durch die anhand der Breakpoints durchdsteppen.Wie
gesagt, die Datei wird geöffnet (z.B von fopen) nur es kommen einfach keine Zeichen aus der Textdatei in den Buffer.-Unter VC++ 6 und VC 7 läuft es ohne Probleme, nur halt nicht bei VS 2005, VS2008,
VS2010. Egal ob Express oder Ultimate Edition. Egal ob ohne seperat installiertes
WinSDK 7.1, scanf und co liefern nicht ein einziges Textzeichen aus der Textdatei
zurück-Mein nächster Schritt wird wohl sein mir das ganze aus Assemblerebene anzuschauen,
vielleicht kann ich einen Unterschied zwischen der Dummy Exe und dem Hauptprojekt
finden.
Peter- Bearbeitet Peter S. Meyer Mittwoch, 5. Dezember 2012 22:20
Alle Antworten
-
Was heißt auf Assembler Ebene?
Du kannst doch in fgetchar hinein debuggen. Du hast doch den Source-Code.Mal was ganz anderes: Wo liegt die Datei? Wie wird sie geöffnet? Nur lesend, oder lesend schreibend?
Was passiert wenn Du das Programm "Als Admin" startest?PS: Wenn mehrere Compiler und Lis zu dem selben Fehler führen stimmt was nicht in Deinem Code.
Martin Richter -- MVP for VC++ [Germany] -- http://blog.m-ri.de
-
So schaut mein Testcode aus.
Wie bereits beschrieben funktioniert er in einer dummy.exe aber nicht in meinem
migrierten Hauptprojekt. Der Code funktioniert ebenfalls unter Linux mit dem GCC und
auf Mac OS X mit dem XCode Compiler.#define _CRT_SECURE_NO_WARNINGS #define _CRT_NONSTDC_NO_DEPRECATE #include <stdio.h> #include <iostream> using namespace std; #ifdef WIN32 #include <direct.h> #else #include <unistd.h> #endif std::string getCurrentDir() { try { char temp[FILENAME_MAX]; return ( getcwd(temp, FILENAME_MAX) ?string( temp ) : string("")); } catch(std::exception) { throw; } } int main () { FILE * fp; int c; int n = 0; std::string myfile = getCurrentDir() += "/testo.txt"; fp=fopen (myfile.c_str(),"r"); if (fp !=NULL) { printf("Using: %s",myfile.c_str()); do { c = fgetc (fp); if (c == '@') n++; } while (c != EOF); fclose (fp); printf ("\nThe file contains %d (@) characters.\n",n); } else { perror ("\nException "); } printf("\nDone."); getchar(); return 0; }
[quote]
Hast Du schon mal reindebugged?
[/quote]
Ja, und der Debugger gibt mir auch nur blanks. Es tritt auch keine Exception in irgend einer Form auch, einfach nichts. AppVerifier und WinDBG habe ich auch schon versucht, habe auf VC++ 2010 auch schon einen App Crashdump gesichert und mir im WinDBG angeschaut aber auch daraus werde ich nicht schlau.
Momentan habe ich die Vermutung das es irgendwie mit den Projectsettings für die App
Stackframes zusammenhängt. Ich werde mal versuchen mittels manueller allokierung den
Buffer auf den Heap zu verlagern. Wenn es irgendwas mit dem Stackframe zu tun hat, sollte
es hier nicht auftreten, das ist aber wie gesagt nur eine Vermutung.
Update:
Daten im Heap bleiben von dem Phänomen auch nicht ausgespart.So langsam gehen mir die Ideen aus. Eventuell könnte ich versuchen das Solutionfile nach CMake zu portieren um es dann von dort zu re-exportieren, in der Hoffnung das CMake keine Zicken macht bei der Migration nur ist das jede Menge Handarbeit die wohl Tage dauern wird und das Ergebnis ist ungewiss.Peter
- Bearbeitet Peter S. Meyer Donnerstag, 6. Dezember 2012 14:31
-
Um es noch mal auf einen blick zu bringen (war ja viel Text)
Dieser Quelltext funktioniert in einem neu erstellten Win32 Konsolenprojekt
int _tmain(int argc, _TCHAR* argv[]) { int c; int n = 0; FILE * fp; fp=fopen ("F:\\testo.txt","r"); if (fp !=NULL) { int c; do { c = fgetc (fp); if (c == '@') n++; } while (c != EOF); fclose (fp); printf ("\nThe file contains %d (@) characters.\n",n); } else { perror ("\nException "); } getchar(); return 0; }
Jedoch funktioniert er NICHT wenn ich den selben Code in meinem großen Hauptprojekt
einbaue! Die Variable n liefert immer 0 zurück, da fgetchar() nicht an die Textdaten
aus der der Datei F:\testo.txt drankommt obwohl die Datei geöffnet ist.
Wie gesagt, in der Dummy Exe klappt der selbe Code. Da der Intel Compiler den selben Code produziert habe ich hier MSBuild/Nmake im verdacht. Da muss irgend ein Schalter in den Pojektsettings sein der mir alles vergeigt.Peter
- Bearbeitet Peter S. Meyer Donnerstag, 6. Dezember 2012 14:53
-
Lege ein leeres C/C++ Projekt an.
Füge alle Deinen Sourcemodule hinzu und mach mal einen Build.
Evtl. hast Du irgendweinen verrückten Compilerswitch verwendet.
Hast Du mit pragma pack gearbeitet?Martin Richter -- MVP for VC++ [Germany] -- http://blog.m-ri.de
-
@Martin
Wie oben beschrieben habe ich das schon versucht (und nicht nur einmal).
Die Compilerswitches sind so wie sie vor der Migration auch waren aber natürlich habe ich sie mir angeschaut und wenn ich einen Switch verändert habe und es nichts gebracht hat, so habe ich ihn auf die vorherige Stellung zurück gestellt. Ich habe nun auch schon mehrfach den Migrationsschrittvon Visual Studio 2003 C/C++ 7.1 auf Visual Studio 2010 SP1 wiederholt, immer mit dem selben Ergebnis. Unter Visual Studio 2003 läuft es aber unter jeder höheren Versions 2005/2008/2010 läuft es nach der Konvertierung mittels des Konvertierungsassistenten von Visual Studio nicht mehr.Es kommt immer zu dem obig beschrieben Fehler: fgetchar, fscanf können
nicht auf die via fopen geöffnete Datei zugreifen. Es werden keine Zeichen in die Zielvariable geschrieben. Das selbe passiert übrigens auch wenn man mittels ifstream
die Datei öffnen und lesen möchte. Nicht in einem neu erstellten TestDumm.Exe Projekt
aber in meinem 2 Millionen Zeilen Visual Studio 2003 VC++ 7.1 Altprojekt das ich migrieren muss (ich habe es nur übernommen, die alten Programmierer sind nicht mehr verfügbar).Peter
- Bearbeitet Peter S. Meyer Donnerstag, 6. Dezember 2012 15:24
-
@Jochen
Habe ich gerade versucht (rb, rt) hat nichts gebracht.
Folgede Datei encondigs und charactersets habe ich getestet
linux_text.txt (erstellt unter Linux mittels VI, file indentifiziert es als ASCII Text)
testo_ansi.txt (standard windows ansi)
testo_ini.txt (windows ini, registry kodiertes fileformat)
testo_littlee.txt (little endian encoding)
testo_msdos.txt (ms dos ascii text)
testo_utf8.txt (utf8 kodiert und alle Zeichen in der Datei nachträchlich utf8 konvertiert)
vs2010_txt.txt (Datei/Neu innerhalb von VS2010 als Textdaei neu erstellt).
Hat leider alles nichts gebracht!
Es wird sogar noch verrückter, wenn man das noch toppen kann...
Dieser Code erstellt erst die Datei f:\temp\testfile.txt und soll sie dann direkt
wieder einlesen. In einer dummy Test Exe klappt alles wie es soll, in meinem migrierten
Projekt wird zwar die Datei korrekt geschrieben aber nicht gelesen!#include <stdio.h> int main() { FILE *fp1; int i1; fp1 = fopen("f:\\temp\\testfile.txt", "w"); if(fp1 == NULL) { printf("cannot create file.\n"); }else { for(i1=0; i1<26; i1++) { fputc(i1+65, fp1); } fputc(10, fp1); fclose(fp1); } // .. bis hier ist alles ok! FILE *fp2; int temp; fp2 = fopen("f:\\temp\\testfile.txt", "r"); if(fp2 == NULL) { printf("cannot open file.\n"); } else { // <--- auch ok, Datei ist korrekt geöffnet! while((temp = fgetc(fp2))!=EOF) { // <-- ab hier geht es schief! printf("%c ", temp); } fclose(fp2); } getchar(); }
- Bearbeitet Peter S. Meyer Donnerstag, 6. Dezember 2012 17:14
-
@Jochen
Ich denke dein Verdacht ging in die richtige Richtung, aber vermutlich anders als Du es vermuten würdest.Ich war gerade drauf und dran und wollte mir die Readfile Function anschauen als ich durch reinen Zufall in der Projektcodebase (wie gesagt das Projekt ist riesig und mir noch nicht vollständig klar) auf Überschreibungen aufmerksam geworden bin, die unter anderen auch so Sachen wie fopen und co einfach überschreiben. Ironischerweise ist da auch noch ein kurzer Comment aus dem Jahr 1996! dabei dass das angeblich notwendig war, weil Visual C/C++
damals einen massiven Bug hatte.
Mir schwahnt übles...Wenn ich mir die ganzen Overrides anschaue dann wundert mich ehrlich gesagt gar nichts mehr. Dummerweise kann ich die nicht mal eben einfach da jeder fgetchar, fscanf, ifstream Aufruf immer erst auf diesen Code umgeleitet wird. Das Problem betrifft statische Libs (*.lib) ebenso wie statisch gelinkte DLL's.
Ich denke ich habe wohl nur zwei Möglichkeiten. Entweder massives Refactoring (was wohl
das beste und sauberste wäre) oder die Aufrufe in eine eigenständige DLL auslagern die
dann via Loadlib bestimmte Funktionen bereit stellt und abgeschottet vom Hauptprogramm
sind. Wer weiß vielleicht reicht es auch erstmal wenn ich nur die Aufrufe auf fscanf und fgetchar
bereinige. So ein mist, naja nützt nichts.