在 std::string 中滥用 GL 信息记录空终止字符?

Misuse of GL info log null terminating character in std::string?

我有一个相当简单的 log() 方法用于 GL 着色器和程序方便 类,因为相应的 compilelink 方法只有 return a bool,同时隐藏所有 GL 调用;例如,

std::string
glShader::log () const
{
    std::string info;
    GLint len = 0;

    if (!glIsShader(gl_shader_obj))
        info = "(invalid shader object)\n";
    else
        glGetShaderiv(gl_shader_obj, GL_INFO_LOG_LENGTH, & len);

    if (len != 0)
    {
        info.resize(static_cast<std::string::size_type>(len));
        glGetShaderInfoLog(gl_shader_obj, len, NULL, & info[0]);
    }

    return info;
}

这是对 std::string::resize (size_type) 论点的误用吗?我知道 C++11 在查询时强制使用空终止字符,即 c_str();但它能保证它在存储中的存在吗?这可能是实现 string 以简化 C 字符串访问的 'reasonable' 方法,但不是必需的。

但是,GL_INFO_LOG_LENGTH在日志的字符数中包括[=20=],前提是有日志;否则日志长度只是零。

我是否可能以这种方式写入超过 string 的保留缓冲区的末尾?我应该在 InfoLog 调用中使用 (len - 1) 吗?还是我对 C++11 字符串的理解有误?也就是说,我可以安全地用空终止符覆盖吗?

是的,这是 std::string 的有效用法。只要不超出范围 [0, size()).

就可以获得指向第一个字符的指针并写入字符数组

但是,你确实犯了一个错误。请参阅,GL_INFO_LOG_LENGTH 在长度中包含 NUL 终止符。这意味着,从技术上讲,您的 std::string 比需要的长了一个字符。 info 的最后一个字符将是 NUL 字符,std::string 会将其视为字符串数据的一部分,而不是标记字符串结尾的定界符。

你应该而不是尝试通过在设置info的大小之前从len中减去1来解决这个问题。为什么?因为glGetShaderInfoLog总是 NUL终止它写入的字符串。因此,如果您收缩 len,它会从日志中删除最后一个实际字符。

相反,您应该在从 OpenGL 复制后缩小 info

info.resize(static_cast<std::string::size_type>(len));
glGetShaderInfoLog(gl_shader_obj, len, NULL, & info[0]);
info.pop_back();

在 C++17 中,标准措辞已更改为允许写入字符串的 NUL 终止符,只要您用 NUL 字符覆盖它即可。它还允许 string::data 到 return 非 const 字符数组。因此,这现在可以正常工作了:

info.resize(static_cast<std::string::size_type>(len - 1));
glGetShaderInfoLog(gl_shader_obj, len, NULL, info.data());

标准要求 info 中有 size+1 个字节。