You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用ifstream读取GLSL着色器文件异常:顶点着色器读取错误

GLSL着色器文件读取异常问题排查与解决

问题现象

在C++项目中读取GLSL着色器文件时出现异常:读取顶点着色器后,输出内容却是片元着色器的最后几行,片元着色器读取正常;使用GDB调试时控制台出现乱码,手动重新输入文件内容也无法解决问题。

相关代码与输出

调用代码

char* vertexShaderSource;
char* fragmentShaderSource;

std::string pathToVertexShader = "./src/shaders/vertexShader.vert";
std::string pathToFragmentShader = "./src/shaders/fragmentShader.frag";

readFileToString(pathToVertexShader, &vertexShaderSource);
readFileToString(pathToFragmentShader, &fragmentShaderSource);

std::cout << vertexShaderSource << std::endl;
std::cout << fragmentShaderSource << std::endl;

控制台输出(vertexShaderSource内容)

5, 0.2, 1.0); <--- thats it?
}

#version 330 core

out vec4 FragColor;

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

readFileToString函数实现

void readFileToString(std::string pathToFile, char** fileContentCString) {
   std::string fileContent;
   std::ifstream filestream(pathToFile);
   if (!filestream) {
      std::cerr << "Failed to load file: " << pathToFile << std::endl;
      return;
   }

   std::string currentLine;
   while (getline(filestream, currentLine)) {
       fileContent += currentLine + "\n";
   }

   filestream.close();

   *fileContentCString = (char*)fileContent.c_str();
}

编译命令

g++ -g -I./include -I./src -L./lib src/glad.c src/main.cpp src/window.cpp -lglfw3dll -o donut.exe

问题根源

核心问题在于readFileToString函数中,fileContent是函数内的局部std::string对象,当函数执行完毕后,该对象会被销毁,其内部的字符缓冲区也会被释放。而fileContent.c_str()返回的指针仅指向这个临时缓冲区,函数结束后,这个指针就变成了野指针。

两次调用该函数时,第二个局部std::string对象(读取片元着色器时的fileContent)会复用之前第一个std::string对象释放的内存空间,导致vertexShaderSource这个野指针最终指向了第二个std::string的缓冲区,所以输出的是片元着色器的内容。GDB调试时的乱码也是野指针访问无效内存导致的。

解决方案

方案1:返回std::string(推荐,无需手动管理内存)

修改函数返回std::string,在调用处使用c_str()获取指针:

std::string readFileToString(std::string pathToFile) {
   std::string fileContent;
   std::ifstream filestream(pathToFile);
   if (!filestream) {
      std::cerr << "Failed to load file: " << pathToFile << std::endl;
      return "";
   }

   std::string currentLine;
   while (getline(filestream, currentLine)) {
       fileContent += currentLine + "\n";
   }

   filestream.close();
   return fileContent;
}

调用代码修改为:

std::string vertexShaderStr = readFileToString(pathToVertexShader);
std::string fragmentShaderStr = readFileToString(pathToFragmentShader);

const char* vertexShaderSource = vertexShaderStr.c_str();
const char* fragmentShaderSource = fragmentShaderStr.c_str();

std::cout << vertexShaderSource << std::endl;
std::cout << fragmentShaderSource << std::endl;

方案2:手动分配堆内存(需注意内存释放)

如果必须返回char*,可以在函数内部分配堆内存,将字符串内容复制过去:

void readFileToString(std::string pathToFile, char** fileContentCString) {
   std::string fileContent;
   std::ifstream filestream(pathToFile);
   if (!filestream) {
      std::cerr << "Failed to load file: " << pathToFile << std::endl;
      *fileContentCString = nullptr;
      return;
   }

   std::string currentLine;
   while (getline(filestream, currentLine)) {
       fileContent += currentLine + "\n";
   }

   filestream.close();

   // 分配堆内存并复制内容
   *fileContentCString = new char[fileContent.size() + 1];
   strcpy(*fileContentCString, fileContent.c_str());
}

使用后记得释放内存,避免泄漏:

// 使用完后
delete[] vertexShaderSource;
delete[] fragmentShaderSource;

方案3:使用智能指针管理内存(更安全)

用std::unique_ptr自动管理内存,避免手动释放的麻烦:

#include <memory>

std::unique_ptr<char[]> readFileToString(std::string pathToFile) {
   std::string fileContent;
   std::ifstream filestream(pathToFile);
   if (!filestream) {
      std::cerr << "Failed to load file: " << pathToFile << std::endl;
      return nullptr;
   }

   std::string currentLine;
   while (getline(filestream, currentLine)) {
       fileContent += currentLine + "\n";
   }

   filestream.close();

   std::unique_ptr<char[]> buf(new char[fileContent.size() + 1]);
   strcpy(buf.get(), fileContent.c_str());
   return buf;
}

调用代码:

auto vertexShaderSource = readFileToString(pathToVertexShader);
auto fragmentShaderSource = readFileToString(pathToFragmentShader);

std::cout << vertexShaderSource.get() << std::endl;
std::cout << fragmentShaderSource.get() << std::endl;

内容的提问来源于stack exchange,提问作者Lance Dy Chua

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 10:35:06