-4

今天我尝试整理一个简单的 OpenGL 着色器类,它从文件中加载文本,根据一些(非常甜美的)自定义语法(例如,编写“ .variing [type] [name];" 将允许您在两个着色器中定义一个可变变量,同时只编写一次,与 ".version" 相同,) 然后使用两者编译 OpenGL 着色器程序,然后标记着色器类当且仅当着色器代码正确编译时为“就绪”。

现在,我做了这一切,但后来遇到了最奇怪(坦率地说有点可怕)的问题。我设置了所有东西,用一些包含有效着色器代码的文件声明了一个新的 'tt::Shader',只是让它告诉我着色器无效,但是当我询问错误是什么时给了我一个空字符串(这意味着OpenGL 给了我一个空字符串,因为它是从那里得到的。)

我再次尝试,这次使用了明显无效的着色器代码,虽然它识别出着色器无效,但它仍然没有给我任何关于错误是什么的信息,只是一个空字符串(我认为显然错误识别部分它也和以前一样。)

感到困惑的是,我手动将两个着色器(有效和无效的着色器)作为字符串重新编写,直接用字符串再次编译类,没有文件访问权限。这样做,错误消失了,第一个编译正确,第二个失败但正确识别了错误是什么。

更困惑的是,我开始将文件中的字符串与我自己编写的字符串进行比较。原来前者比梯子长一点,尽管打印相同。数了数之后,我意识到这些字符一定是在导入过程中被截断的 Windows CR LF 行尾回车字符。

为了测试这一点,我拿起手写的字符串,在它们将被切断的地方插入马车,然后再次运行我的字符串比较测试。这一次,它评价theres长度相同,但还告诉我,两者仍然不相等,这很令人费解。

因此,我编写了一个简单的 for 循环来遍历两个字符串的字符,然后将每个字符串彼此相邻打印,然后转换为整数,这样我就可以看到它们的索引值。我运行程序,浏览了(相当长的)列表,并得出了一个不同的有见地但更不明确的答案:隐藏的字符在正确的位置,但它们不是马车......它们是空终止符!

这是我正在使用的文件读取功能的代码。这没什么花哨的,只是标准库的东西。

// Attempts to read the file with the given path, returning a string of its contents.
// If the file could not be found and read, an empty string will be returned.
// File strings are build by reading the file line-by-line and assembling a single with new lines placed between them.
// Given this line-by-line method, take note that it will copy no more than 4096 bytes from a single line before moving on.
inline std::string fileRead(const std::string& path) {


    if (!tt::fileExists(path))
        return "";
    std::ifstream a;
    a.open(path);
    std::string r;
    const tt::uint32 _LIMIT = 4096;
    char r0[_LIMIT];

    tt::uint32 i = 0;
    while (a.good()) {
        a.getline(r0, _LIMIT);
        if (i > 0)
            r += "\n";
        i++;
        r += std::string(r0, static_cast<tt::uint32>(a.gcount()));
    }

    // TODO: Ask StackOverflow why on earth our file reading function is placing null characters where excess carriages should go.

    for (tt::uint32 i = 0; i < r.length(); i++)
        if (r[i] == '\0')
            r[i] = '\r';
    a.close();
    tt::printL("Reading file '" + path + "' ...");
    return r;
}

如果你们都可以阅读并告诉我到底发生了什么,那就太棒了,因为我完全不知道它对我的琴弦做了什么导致这种情况。

最后,我确实明白为什么空终止符没有出现在我面前,但对于 OpenGL 却出现了,梯子使用 C 字符串,而我只是用 std::string 对象做所有事情,其中​​根据给定的长度存储东西他们几乎只是花哨的 std::vector 对象。

4

1 回答 1

1

阅读构造函数的文档。无论输入如何,std::string构造函数std::string(const char*, size_t n)都会创建大小字符串。n它可能在内部包含空字符,甚至超过 1。请注意,大小std::string不包括空字符(因此str[str.size()] == '\0'总是如此)。

getline很明显,代码只是从函数的输出缓冲区复制空字符。

为什么会这样做?转到gcount()函数文档- 它返回最后一次操作提取的字符数。即,它包括\n在输出中被替换的提取字符\0。构造函数要求的正好多一个数字。

所以要修复它只需替换:

r += std::string(r0, static_cast<tt::uint32>(a.gcount()-1));

或者您可以简单地使用getline()withstd::string作为输入而不是缓冲区 - 而这一切都不会发生。

于 2020-03-27T07:40:47.867 回答