Trouble reading shaders using fstream

I’m having trouble getting fstream to work with my shader files.
This is the runtime error:

    (0) : error C0201: unsupported version 0
    (0) : error C0206: invalid token "<null atom>" in version line

Here is my source:
(vs.glsl)


	layout (location = 0) in vec3 aPos;

	void main()
	{
		gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
	}

(fs.glsl)

	#version 330 core

	out vec4 FragColor;

	void main()
	{
		FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);
	}

(main.cpp)

	#include <GL/glew.h>
	#include <GLFW/glfw3.h>
	
	#include <iostream>
	#include <fstream>
	#include <string>


	void framebuffer_size_callback(GLFWwindow* window, int width, int height); 
	void processInput(GLFWwindow *window);

	const unsigned int SCR_WIDTH = 800;
	const unsigned int SCR_HEIGHT = 600;

	int main(void)
	{
	/* --- Initialize and configure GLFW ----------------------------------------------------------------------------------------------------------------------------- */
		if (!glfwInit()) {
			std::cout << "Failed to initialize GLFW\n";
			return -1;
		}
		
		glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
		glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
		glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

	#ifdef __APPLE__
		glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
	#endif

	/* --- Window Creation ------------------------------------------------------------------------------------------------------------------------------------------- */
		GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "OpenGL", NULL, NULL);
		if (!window) {
			std::cout << "Failed to create window\n";
			glfwTerminate();
			return -1;
		}
		glfwMakeContextCurrent(window);
		
		// Setup the viewport
		glViewport(0, 0, SCR_WIDTH, SCR_HEIGHT);
		glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
		std::cout << glGetString(GL_VERSION) << "\n";
		
		// Initialize GLEW
		if (glewInit() != GLEW_OK) {
			std::cout << "Failed to initialize GLEW\n";
			glfwTerminate();
			return -1;
		}

	/* --- Shaders --------------------------------------------------------------------------------------------------------------------------------------------------- */
		// Load and process shader files
		std::ifstream fileInput;
		std::string srcString;
		std::cout << "Reading vertex shader\n";
		fileInput.open("vs.glsl");
		fileInput >> srcString;
		const char* vertexShaderSource = srcString.c_str();
		fileInput.close();
		std::cout << "Reading fragment shader\n";
		fileInput.open("fs.glsl");
		fileInput >> srcString;
		const char* fragmentShaderSource = srcString.c_str();
		fileInput.close();
		
		// Compile shaders
		// vertex shader
		int vertexShader = glCreateShader(GL_VERTEX_SHADER);
		glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
		glCompileShader(vertexShader);
		// check for shader compile errors
		int success;
		char infoLog[512];
		glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
		if (!success)
		{
			glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
			std::cout << "ERROR : Vertex shader compilation failed\n" << infoLog << std::endl;
		}
		// fragment shader
		int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
		glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
		glCompileShader(fragmentShader);
		// check for shader compile errors
		glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
		if (!success)
		{
			glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
			std::cout << "ERROR : Fragment shader compilation failed\n" << infoLog << std::endl;
		}
		// link shaders
		int shaderProgram = glCreateProgram();
		glAttachShader(shaderProgram, vertexShader);
		glAttachShader(shaderProgram, fragmentShader);
		glLinkProgram(shaderProgram);
		// check for linking errors
		glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
		if (!success) {
			glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
			std::cout << "ERROR : Shader program failed to link\n" << infoLog << std::endl;
		}
		glDeleteShader(vertexShader);
		glDeleteShader(fragmentShader);	
		
	/* --- Vertex Buffer Object, Vertex Array Object, Element Buffer Object ------------------------------------------------------------------------------------------ */
		float vertices[] = {
			 0.5f,  0.5f, 0.0f,  // top right
			 0.5f, -0.5f, 0.0f,  // bottom right
			-0.5f, -0.5f, 0.0f,  // bottom left
			-0.5f,  0.5f, 0.0f   // top left 
		};
		unsigned int indices[] = {
			0, 1, 3,  // first Triangle
			1, 2, 3   // second Triangle
		};
		
		unsigned int vbo_id, vao_id, ebo_id;
		// Generate VAO 
		glGenVertexArrays(1, &vao_id);
		glBindVertexArray(vao_id);
		// Generate VBO
		glGenBuffers(1, &vbo_id);
		glGenBuffers(1, &ebo_id);
		// Fill VBO with data
		glBindBuffer(GL_ARRAY_BUFFER, vbo_id);
		glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
		// Fill EBO with data
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo_id);
		glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
		// Configure VAO
		glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 3, (void*)0);
		glEnableVertexAttribArray(0);
		// Unbind Vertex Buffer Object
		glBindBuffer(GL_ARRAY_BUFFER, 0);
		// Unbind Vertex Array Object 
		//glBindVertexArray(0);
		// Set clear color
		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
		// Render Wireframe
		glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

	/* --- Game Loop ------------------------------------------------------------------------------------------------------------------------------------------------- */
		while (!glfwWindowShouldClose(window)) {
			// Render here
			glClear(GL_COLOR_BUFFER_BIT);
			
			// Draw triangle
			glUseProgram(shaderProgram);
			glBindVertexArray(vao_id);
			glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
			glBindVertexArray(0);

			// Swap front and back buffers
			glfwSwapBuffers(window);

			// Poll for and process events
			glfwPollEvents();
			processInput(window);
		}
	/* --- Termination ----------------------------------------------------------------------------------------------------------------------------------------------- */
		// De-allocate buffers and shaders in VRAM
		glDeleteVertexArrays(1, &vao_id);
		glDeleteBuffers(1, &vbo_id);
		glDeleteBuffers(1, &ebo_id);
		glDeleteProgram(shaderProgram);

		// Terminate GLFW and return program success
		glfwTerminate();
		return 0;
	}

	void framebuffer_size_callback(GLFWwindow* window, int width, int height)
	{
		glViewport(0, 0, width, height);
	}  

	void processInput(GLFWwindow *window)
	{
		if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
			glfwSetWindowShouldClose(window, true);
		}
	}

Full output:

4.6.0 NVIDIA 450.57
Reading vertex shader
Reading fragment shader
ERROR : Vertex shader compilation failed
(0) : error C0201: unsupported version 0
(0) : error C0206: invalid token "<null atom>" in version line

ERROR : Fragment shader compilation failed
(0) : error C0201: unsupported version 0
(0) : error C0206: invalid token "<null atom>" in version line

ERROR : Shader program failed to link
Vertex info
-----------
(0) : error C0201: unsupported version 0
(0) : error C0206: invalid token "<null atom>" in version line
(0) : error C2003: incompatible options for link

Fragment info
-------------
(0) : error C0201: unsupported version 0
(0) : error C0206: invalid token "<null atom>" in version line
(0) : error C2003: incompatible options for link

Have you checked the contents of srcString? IIRC operator>>(std::istream& is, std::string& str) only reads up to the first whitespace (see cppreference.com). I believe the shader code passed to OpenGL is only “#version” which is somewhat consistent with the error about version 0 not being supported.

This won’t work. The second >> overwrites srcString which invalidates the pointer returned by .c_str(). You need to either use two distinct std::string objects or defer reading the fragment shader until you’ve finished using the text of the vertex shader.

More generally, any iterators or pointers returned from std::string methods are invalidated by any method which may reallocate the string object’s underlying buffer.

I have rewritten shader loading code to be like this, now throwing std::bad_alloc.

	// Load and process shader files
	std::ifstream fileInput;
	std::streampos fileSize;
	char* srcString;
	
	// --- vertex shader
	fileInput.open("vs.glsl");
	if(fileInput.is_open()) {
		std::cout << "Reading vertex shader\n";
		fileSize = fileInput.tellg();
		srcString = new char[fileSize];
		fileInput.seekg(0, std::ios::beg);
		fileInput.read(srcString, fileSize);
		fileInput.close();
	} else {
		std::cout << "Vertex shader failed to open\n";
		return -1;
	}
	const char* vertexShaderSource = srcString;
	delete[] srcString;
	
	// --- fragment shader
	fileInput.open("fs.glsl");
	if(fileInput.is_open()) {
		std::cout << "Reading fragment shader\n";
		fileSize = fileInput.tellg();
		srcString = new char[fileSize];
		fileInput.seekg(0, std::ios::beg);
		fileInput.read(srcString, fileSize);
		fileInput.close();
	} else {
		std::cout << "Fragment shader failed to open\n";
		return -1;
	}
	const char* fragmentShaderSource = srcString;
	delete[] srcString;
	
	// Compile shaders
	// --- vertex shader
	int vertexShader = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
	glCompileShader(vertexShader);
	// --- check for shader compile errors
	int success;
	char infoLog[512];
	glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
	if (!success)
	{
		glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
		std::cout << "ERROR : Vertex shader compilation failed\n" << infoLog << std::endl;
	}
	// --- fragment shader
	int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
	glCompileShader(fragmentShader);
	// --- check for shader compile errors
	glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
	if (!success)
	{
		glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
		std::cout << "ERROR : Fragment shader compilation failed\n" << infoLog << std::endl;
	}
	
	// link shaders
	int shaderProgram = glCreateProgram();
	glAttachShader(shaderProgram, vertexShader);
	glAttachShader(shaderProgram, fragmentShader);
	glLinkProgram(shaderProgram);
	// --- check for linking errors
	glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
	if (!success) {
		glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
		std::cout << "ERROR : Shader program failed to link\n" << infoLog << std::endl;
	}
	glDeleteShader(vertexShader);
	glDeleteShader(fragmentShader);

Output:

lou@debian:~/Development/OpenGL$ ./opengl 
4.6.0 NVIDIA 450.57
Reading vertex shader
Reading fragment shader
ERROR : Vertex shader compilation failed
0(1) : error C0000: syntax error, unexpected $undefined at token "<undefined>"

ERROR : Fragment shader compilation failed
0(1) : error C0000: syntax error, unexpected $undefined at token "<undefined>"

ERROR : Shader program failed to link
Vertex info
-----------
0(1) : error C0000: syntax error, unexpected $undefined at token "<undefined>"
(0) : error C2003: incompatible options for link

Fragment info
-------------
0(1) : error C0000: syntax error, unexpected $undefined at token "<undefined>"
(0) : error C2003: incompatible options for link

This is also wrong. If you’ve just opened a file (and didn’t use the ios::ate flag), .tellg() will return 0 (or pos_type(-1) if there’s an error). If you want to use .tellg() to get the size, the position indicator must be at the end of the file (and on Windows, the file must have been opened in binary mode; otherwise the position indicator is going to count CR+LF as two bytes although only one byte will be read).

So far, all your problems have been about reading a file in C++ and nothing to do with OpenGL. I suggest using a debugger to check what’s actually in the string you’re passing to glShaderSource. Until that’s correct, you’d do better to ask on a C++ or general programming forum than one dedicated to OpenGL.

Well, with your help I think I’ve fixed the issue for file input. Is there a general programming forum you recommend? I don’t want to join one specific to C++ as after I complete the render engine, I’d like to use Lua to write basically the rest of the engine, rewritting the bits I see necessary into C++. Returning to issues being had however, I now am getting this output,

4.6.0 NVIDIA 450.57
Reading vertex shader
Reading fragment shader
ERROR : Shader program linking failed
Vertex info
(0) : error C5145: must write to gl_Position
	fileInput.open("vs.glsl", std::ios::in | std::ios::binary);
	...
	std::cout << "Reading vertex shader\n";
	fileInput.seekg(0, std::ios::end);
	fileSize = fileInput.tellg();
	srcString = new char[fileSize];
	fileInput.seekg(0, std::ios::beg);
	fileInput.read(srcString, fileSize);
	fileInput.close();

vs.glsl

	#version 460 core

	layout (location = 0) in vec3 aPos;

	void main()
	{
		gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
	}

This too is wrong. Deleting srcString means that vertexShaderSource points to memory which is marked for re-use. Whether you use std::string or char[], you must keep the underlying data around until you’ve finished using it. Copying a pointer doesn’t make a copy of the data.

Use a debugger. Set a breakpoint on the line containing the glShaderSource call. When that breakpoint triggers, inspect the variable whose address is being passed to the call and verify that it contains what you expect.

Breakpoint 1, main () at main.cpp:95
95		glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
(gdb) print &vertexShaderSource
$1 = (const char **) 0x7fffffffdeb8
(gdb) print vertexShaderSource
$2 = 0x555555a9f970 ""

It’s an empty string.
My solution is simply to rearrange the code to compile before deleting the srcString and it works.

I am curious to know if there is a specific forum you recommend?

When I was learning I mainly used usenet groups (e.g. comp.lang.c++), but I have no idea if they’re still relevant today.