【问题标题】:How to pass an std::string to glShaderSource?如何将 std::string 传递给 glShaderSource?
【发布时间】:2011-08-28 04:46:36
【问题描述】:

我有以下代码:

glShaderSource(shader, 1, (const char **)data.c_str(), NULL);

但这会使我的程序崩溃。如何将 std::string 转换为 const char ** ? 我也试过(const char **)&,但它说“需要左值”,我不明白。当我使用此代码时它工作正常:

const char *data = "some code";
glShaderSource(shader, 1, &data, NULL);

但我不能直接通过std::string 让它工作。我可以为它分配一个新的char 数组,但这不是很好的代码。

我也试过const GLchar,但显然没有区别。

【问题讨论】:

  • 查看该函数的文档。必须有一个原因它需要一个指向指针的指针。假设这是一个输出参数,函数写入一个char* 到取消引用的char**。在这种情况下,您需要传递真实指针的地址,而不是 std::string::c_str() 返回的一些临时地址。
  • @sbi: 这不是一个输出参数,它需要一个 c 字符串数组。
  • @Benjamin:啊,是的,我忘记了这种可能性。
  • 我认为这个问题又是一个“为什么我不能……”,而真正的问题应该是“你为什么想要?”。您正在转换为不兼容的指针类型。它不应该工作。我认为它应该让你停止思考你对glShaderSource不了解的地方。 15 秒的谷歌会告诉你第三个参数“指定一个指针数组,指向包含要加载到着色器中的源代码的字符串。”。您的问题的标题完全具有误导性:您不能进行这样的转换。

标签: c++ string opengl char


【解决方案1】:

data.c_str() 返回一个const char*,所以这样做:

const char *c_str = data.c_str();
glShaderSource(shader, 1, &c_str, NULL);

【讨论】:

  • 是否有可能从中删除变量声明并将其放到我调用函数的那一行?
  • @Rookie - 声明,但不初始化,c_str 某处:const char*c_str;。然后,在使用点,试试这个:glShaderSource(shader, 1, &(c_str=data.c_str()), NULL);
  • 我不认为你可以使用单行。 glShaderSource 需要一个字符串数组(const char** = const char* 的数组),而您的 std::string 只给您一个字符串。您必须添加一级间接,以便glShaderSource 获得一个指针,它可以取消引用以检索字符串。
  • @Rob:请注意,const char* c_str;definition,而不是声明。
  • 我完全同意 Ferdinand Beyer 的观点,因为 glShaderSource 的文档明确告诉您使用 const char* 的数组。
【解决方案2】:

std::string::c_str() 的返回值是指向 std::string 对象的数据结构中保存的静态字符串数组的指针值(即地址)。由于返回 value 只是一个临时的 r 值(即,它只是一个存储在 CPU 寄存器中的数字),它不是一个 l 值,因此它没有你可以使用的内存地址实际上获取并转换为指针的地址。您首先必须将返回指针值保存在内存地址中。内存位置是左值,并且可以将地址运算符应用于它们。这就是为什么您的第二种方法(或 Dark Falcon 的方法)起作用的原因,尽管请记住返回的指针值是临时的,这意味着如果您对 std::string 对象执行任何操作,它可能会使指针无效,因为 @ 987654324@ 对象内部管理其数据结构的内存。因此,仅仅因为您将返回指针值保存在内存位置并不意味着该指针不会在以后的某个时间失效,并且在您可能无法确定性地选择的时候。

【讨论】:

  • c_str() 返回可以赋值给左值
  • @CharlesB:是的,返回值可以赋值给左值,但返回值本身不是左值,因此不能将地址运算符应用于std::string::c_str() 的返回。
  • 好的,但是你的解释有点离题,你不需要这些知识来解决OP问题
  • 抱歉,我只是认为它可能会有所帮助,并可能提供一些背景情况。 OP想知道为什么一种方法有效,而另一种方法无效。打印出有效的代码固然很好,但并不一定会给人们提供工具或理解来避免将来出现类似情况。其他人已经创建了很好的代码示例,所以我想我会更深入地解释为什么一种方式有效而另一种方式无效,以帮助 OP 理解根本问题。
【解决方案3】:

您可以通过使用辅助类来获得看起来合理的调用。定义这个类:

struct StringHelper {
  const char *p;
  StringHelper(const std::string& s) : p(s.c_str()) {}
  operator const char**() { return &p; }
};

那么,当你需要打电话给glShaderSource时,这样做:

glShaderSource(shader, 1, StringHelper(data), NULL);

【讨论】:

  • 我用过这个。我有多个要转换的字符串,我可以把实现代码收起来,在一行中完成所有事情。完美。
【解决方案4】:

glShaderSource签名是,根据glShaderSource doc

void glShaderSource(
    GLuint shader,
    GLsizei count,
    const GLchar** string,
    const GLint* length);

其中string“指定一个指针数组,指向包含要加载到着色器中的源代码的字符串”。您要传递的是指向以 NULL 结尾的字符串的指针(即指向 const char* 的指针)。

不幸的是,我不熟悉glShaderSource,但我猜它不是指向“某些代码”的指针,而是这样的:

const char** options =
{
    "option1",
    "option2"
    // and so on
};

来自opengl-redbook,你可以阅读一个例子(我故意缩短了它):

const GLchar* shaderSrc[] = {
    "void main()",
    "{",
    "    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;",
    "}"
};
shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(shader, NumberOfLines(shaderSrc), shaderSrc, NULL);

【讨论】:

  • +1 实际查看函数文档!
  • @sbi 和@mister,将字符串分成这样的行有什么意义?当所有元素都在数组的第一项中时,它可以正常工作。
  • @Rookie:如果您想传递一个包含多个字符串的数组,这就是您想要的。由于您只想传递一个字符串,我想它不适用于您。
【解决方案5】:

我只想指出c_str() 返回的指针只有在你不做任何需要重新分配std::string 内部缓冲区的事情时才有效。这会使您获得的指针无效。

但既然你真的需要** 我会这样做:

const char* mychararr[1] = {data.c_str()};
glShaderSource(shader, 1, mychararr, NULL);

只要您不离开 mychararr 的范围,这应该可以很好地工作。

【讨论】:

  • 我认为初始化不会编译(在 C++03 中)。
  • @sbi:GCC 对这些事情很满意,但我认为你是对的,它是非标准的。
  • @Tony:我认为它是标准的,但 C++11 标准尚未发布。
  • @sbi:我没有遵循新标准的这方面......这很好:-) 感谢您提供信息。
【解决方案6】:

尝试使用 .c_str() 它会给你一个 char *,你可以使用它,因为它对你有用 b4

#include <string>

void ConversionSample ()
{
 std::string strTest ("This is a string");
 const char* pszConstString = strTest.c_str ();
 }

【讨论】:

    【解决方案7】:

    着色器.cpp

    #include "Shader.hpp"
    
    Shader::Shader(GLenum type)
    {
        this->_type = type;
    }
    Shader::~Shader() {}    
    
    GLuint Shader::get(char* filename)
    {
        GLuint shdr = glCreateShader(this->_type);
        FILE* f = 0;
        f = fopen(filename, "r+");
        char* str_tmp = 0;
        char** shdr_text = 0;
        shdr_text = (char**)malloc(sizeof(char**) * 255);
        str_tmp = (char*)malloc(sizeof(char*) * 255);
        int i = 0, ch = 0, n = 0;
    
        for(i = 0; i < 255; ++i){ *(shdr_text + i) = (char*)malloc(sizeof(char*) * 255); }
    
        i = 0;
        while((ch = fgetc(f)) != EOF)
        {
            sprintf(str_tmp, "%s%c", str_tmp, ch);
            if(ch == (int)'\n' || ch == (int)'\r')
            {
                sprintf(*(shdr_text + i), "%s", str_tmp);
                sprintf(str_tmp, "");
                ++i;
            }
        }
    
        free(str_tmp);
        fclose(f);
    
        glShaderSource(shdr, i, const_cast<const GLchar**>(shdr_text), 0);
        glCompileShader(shdr);
    
        free(shdr_text);
    
        return(shdr);
    }
    

    着色器.hpp

    #ifndef SHADER_HPP
    #define SHADER_HPP
    
    #include <stdlib.h>
    #include <stdio.h>
    #include <GL/glew.h>
    #include <GL/gl.h>
    
    class Shader
    {
        public:
            Shader(GLenum type);
            virtual ~Shader();
    
            GLuint get(char* filename);
    
        private:
            GLenum _type;
    };
    
    #endif
    

    【讨论】:

    • 大+1,归零,螺丝钉,好东西,谢谢发帖。
    猜你喜欢
    • 1970-01-01
    • 2015-09-26
    • 2011-04-18
    • 1970-01-01
    • 1970-01-01
    • 2015-02-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多