none
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


    Mittwoch, 5. Dezember 2012 21:36

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

    Donnerstag, 6. Dezember 2012 07:34
  • Was liefert fscanf für einen Rückgabewert?
    Wie sieht die Code-Zeile genau aus?
    Hast Du schon mal reindebugged?


    Jochen Kalmbach (MVP VC++)
    Donnerstag, 6. Dezember 2012 08:43
  • 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

    Donnerstag, 6. Dezember 2012 12:56
  • 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


    Donnerstag, 6. Dezember 2012 14:50
  • 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

    Donnerstag, 6. Dezember 2012 15:05
  • @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



    Donnerstag, 6. Dezember 2012 15:15
  • Ich kann mir Dein Problem beim besten willen nicht vorstellen... Was für ein Encoding hat denn die Datei?
    Öffne mal die Datei mit "rt" oder "rb"...


    Jochen Kalmbach (MVP VC++)
    Donnerstag, 6. Dezember 2012 15:35
  • @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(); }


    Donnerstag, 6. Dezember 2012 17:04
  • Bitte debugge mal in die fgetc Funktion rein!!!! Und zwar bis zum "ReadFile"! Alles andere bringt nichts!!!


    Jochen Kalmbach (MVP VC++)
    Donnerstag, 6. Dezember 2012 18:54
  • @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.

    Donnerstag, 6. Dezember 2012 21:28