OpenGL - Problem mit 0-Terminierung

thekiller

Viceinator
Hallo,

ich hab grad ein nerviges Problem wo was ich nicht ganz verstehe.

Also ich habe eine Klasse mit einer Methode die eine Textdatei komplett einlesen soll und als OpenGL Shader dient. Vor dem Einlesen ermittle ich die Dateigröße welche auch stimmt. Dann alloziiere ich Speicher für den Inhalt der Datei und lese die Datei ein. Dann will ich den Strink 0-terminieren an der Position => FileSize. Laut VC++ Debugger sind ist nach dem Terminieren immernoch ein paar Zeichen ab der Stelle wo der String eigentlich terminiert sein sollte.

Wenn ich den String FileSize -8 terminiere stimmt der String, dann ist die Stringlänge, ermittelt mit strlen(), aber 173. Irgendwas haut da überhaut nich hin. Hat jemand ne idee?

Beispiel:
Dateiinhalt:
Code:
varying vec3 lightDir, normal;

void main()
{
	lightDir = normalize(vec3(gl_LightSource[0].position));
	normal = gl_NormalMatrix * gl_Normal;

	gl_Position = ftransform();
}

Inhalt von FileContent nach Einlesen der Datei (DEBUGGER):
Code:
varying vec3 lightDir, normal;

void main()
{
	lightDir = normalize(vec3(gl_LightSource[0].position));
	normal = gl_NormalMatrix * gl_Normal;

	gl_Position = ftransform();
}ÍÍÍÍÍÍÍÍÍýýýý««««««««îþîþîþ

Inhalt von FileContent nach Terminierung (DEBUGGER):
Code:
varying vec3 lightDir, normal;

void main()
{
	lightDir = normalize(vec3(gl_LightSource[0].position));
	normal = gl_NormalMatrix * gl_Normal;

	gl_Position = ftransform();
}ÍÍÍÍÍÍÍÍ

Hier mal die Methode:
C++:
	FILE*	File		= NULL;
	uint32	FileSize	= 0;
	char*	FileContent	= NULL;

	File	= fopen(_FileName, "rt"); // _FileName wird der Methode übergeben
	if(File == NULL) {
		throw "LoadShaderFile():\nShaderfile konnte nicht geöffnet werden!";
	}

	fseek(File, 0, SEEK_END);
	FileSize	= ftell(File);    // FileSize ist 181 => stimmt
	fseek(File, 0, SEEK_SET);

	FileContent	= new char[FileSize + 1];
	if(FileContent == NULL) {
		fclose(File);

		throw "LoadShaderFile():\nNicht genug Speicher!";
	}

	fread(FileContent, FileSize, 1, File);
	FileContent[FileSize]	= 0; // FileSize ist laut Debugger 181 => stimmt

	uint32	i	= strlen(FileContent); // i ist 181 => stimmt aber der String enthält mehr als 181 Zeichen************************************

	fclose(File);

	///////////////////////////////////////////////////////////////////////////
	this->VertexShaderHandle	= glCreateShader(GL_VERTEX_SHADER);

	const char*	ShaderText	=	FileContent;
	i	= strlen(ShaderText);
	glShaderSource(this->VertexShaderHandle, 1, &ShaderText, NULL);

	glCompileShader(this->VertexShaderHandle);

	char	buff[1024]	= {0};
	GLsizei	size		= 0;
	glGetShaderInfoLog(this->VertexShaderHandle, 1024, &size, buff);
	///////////////////////////////////////////////////////////////////////////

	delete[]	FileContent;

MfG Manuel
 
Zuletzt bearbeitet von einem Moderator:
Hallo Manuel,

In welcher Kodierung hast du denn deine Textdatei gespeichert. ANSI oder Unicode?

Ansonsten trifft möglicherweise das zu, was in der Referenz steht bzgl. ftell
For text streams, the value is not guaranteed to be the exact number of bytes from the beginning of the file, but the value returned can still be used to restore the position indicator to this position using fseek.

Gruss
Muepe
 
Zuletzt bearbeitet:
Die Datei ist in ANSI Kodiert. Die 181 Byte stimmen auf jedenfall. Mir ist auch unerklärlich wieso der Text dann richtig ist, wenn ich ihn bei 173 terminiere. Dann müssten ja die letzten 8 Zeichen Fehlen.
Also so:

Code:
varying vec3 lightDir, normal;

void main()
{
	lightDir = normalize(vec3(gl_LightSource[0].position));
	normal = gl_NormalMatrix * gl_Normal;

	gl_Position = ftransfo

ftell gibt mir ja auch die 181 zurück. Der Fehler muss ja irgendwie beim Terminieren sein. Als wenn er folgendes macht.

C++:
FileContent[FileSize + 8]	= 0;
 
Zuletzt bearbeitet von einem Moderator:
Das Problem sind die Zeilenumbrüche. In Windows wird die Datei als \r\n gespeichert, nach dem auslesen wird aber nur \n in den Puffer übernommen. Du hast 8 Zeilenumbrüche => ftell gibt 8 Zeichen mehr zurück, als ausgelesen werden.
 
Hallo,

wie Muepe32 schon erwähnt hat, ist die automatische Umwandlung von Zeilenumbrüchen das Problem. Die Lösung ist, die Datei einfach im Binärmodus zu öffnen.

Noch ein paar Anmerkungen zu deinem Code:
  • Bezeichner, die mit einem Unterstrich gefolgt von einem weiteren Unterstrich oder einem Großbuchstaben beginnen, sind für den Compiler reserviert. Solche Namen sollte man auf jeden Fall vermeiden.
  • Der eingebaute new-Operator gibt niemals NULL zurück, sondern wirft im Falle des Falles std::bad_alloc. Es sei denn du verwendest explizit das nothrow new.
  • Eine Frage des (persönlichen) Stils: du musst hier nicht unbedingt die C-Funktionen verwenden, C++ bietet schließlich auch ein API für Datei-E/A an.

Grüße,
Matthias
 
Zurück