在 std::string 中滥用 GL 信息记录空终止字符?
Misuse of GL info log null terminating character in std::string?
我有一个相当简单的 log()
方法用于 GL 着色器和程序方便 类,因为相应的 compile
和 link
方法只有 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 个字节。
我有一个相当简单的 log()
方法用于 GL 着色器和程序方便 类,因为相应的 compile
和 link
方法只有 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 个字节。