从文件读取时字符串已损坏

String getting corrupted when reading from file

本文关键字:字符串 已损坏 读取 文件      更新时间:2023-10-16

我正在使用OpenGL进行一些实验,并尝试加载着色器。它需要const char*中的源代码,但由于我在C++上这样做,我可以使用std::string,然后调用str.C_str()。这不是问题所在——当我尝试读取文件时,它读取得很好,但返回的值是一个损坏的字符串。以下是代码的相关部分:

// inline method on engine.hpp
inline void readFile(std::string filePath, std::string* retValue) 
{
std::ifstream file;
file.open(filePath);
std::string result;
std::string line;
while (!file.eof())
{
    std::getline(file, line);
    result.append(line + "n");
}
    memcpy(retValue, &result, sizeof(result));
}
// implemented method on engine.cpp
GLint Engine::createShader(std::string vs, std::string fs)
{
GLuint vertex = glCreateShader(GL_VERTEX_SHADER);
GLuint fragment = glCreateShader(GL_FRAGMENT_SHADER);
std::string vsSourceStr = "";
std::string fsSourceStr = "";
readFile(vs, &vsSourceStr);
readFile(fs, &fsSourceStr);
const char* vsSource = vsSourceStr.c_str();
const char* fsSource = fsSourceStr.c_str();
//std::string t_vs = readFile(vs);
//const char* vsSource = readFile(vs).c_str();
//const char* fsSource = readFile(fs).c_str();
glShaderSource(vertex, 1, &vsSource, NULL);
glCompileShader(vertex);
glShaderSource(fragment, 1, &fsSource, NULL);
glCompileShader(fragment);
GLint program = glCreateProgram();
glAttachShader(program, vertex);
glAttachShader(program, fragment);
glLinkProgram(program);
if (shaderCompiled(program))
{
    std::cout << "shader successfully compiled" << std::endl;
}
else
{       
    std::cout << "shader not compiled" << std::endl;
    printShaderError(vertex);
    printShaderError(fragment);
    std::cout << "Vertex Shader source:" << std::endl;
    std::cout << vsSource << std::endl;
    std::cout << "Fragment Shader source:" << std::endl;
    std::cout << fsSource << std::endl;
}
return program;
}

以下是Visual Studio关于调试的说明:http://prntscr.com/4qlnx7

它完美地读取了文件,只是破坏了返回值。我已经尝试过使用引用和复制内存来返回结果,正如您在我的代码中看到的那样。无论如何,谢谢。

这不会像你想的那样:

std::string line;
while (!file.eof())
{
    std::getline(file, line);
    result.append(line + "n");
}

请使用:

std::string line;
while (std::getline(file, line))
{
    result.append(line + "n");
}

原因是eof()直到文件被读取之后才被触发。这意味着您的std::getline()可能已经失败(在EOF),并且您正在使用坏数据。

请参阅:关于eof()的C++常见问题15.5。

执行memcpy(retValue, &result, sizeof(result));时,复制的是内部std::字符串结构,而不是字符串数据。改为分配字符串:*retValue = result

在readFile()中使用对结果字符串的引用将获得更健壮的版本:

void readFile(std::string filePath, std::string& retValue) 
{
    std::ifstream file(filePath);
    retValue.clear();
    std::string line;
    while (std::getline(file, line))
    {
        retValue += line;
        retValue += 'n';
    }
}
GLint Engine::createShader(std::string vs, std::string fs)
{
    GLuint vertex = glCreateShader(GL_VERTEX_SHADER);
    GLuint fragment = glCreateShader(GL_FRAGMENT_SHADER);
    std::string vsSourceStr;
    std::string fsSourceStr;
    readFile(vs, vsSourceStr);
    readFile(fs, fsSourceStr);
    // ...
 }

将文件读取为字符串的另一种方法是使用std::istreambuf_iterator:

inline std::string readFile(std::string const& filename)
{
    std::ifstream file(filename);
    std::istreambuf_iterator<char> begin(file), end;
    return std::string(begin, end);
}