Как передать std :: string в glShaderSource? - PullRequest
27 голосов
/ 18 мая 2011

У меня есть следующий код:

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

Но это приводит к сбою моей программы.Как конвертировать std::string в const char **?Я также пытался (const char **)&, но там говорилось, что "требует l-значение", чего я не понимаю.Он прекрасно работает, когда я использую этот код:

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

Но я не могу заставить его работать напрямую с std::string.Я мог бы выделить для него новый массив char, но это не очень хороший код.

Я также пытался использовать const GLchar, но, очевидно, это не имеет значения.

Ответы [ 8 ]

49 голосов
/ 18 мая 2011

data.c_str() возвращает const char*, поэтому сделайте следующее:

const char *c_str = data.c_str();
glShaderSource(shader, 1, &c_str, NULL);
14 голосов
/ 18 мая 2011

Возвращаемое значение std::string::c_str() является значением указателя (то есть адресом) на массив статических строк, содержащийся в структурах данных объекта std::string. Поскольку возвращаемое значение является просто временным r-значением (т. Е. Это просто число, хранящееся в регистре ЦП), оно не является l-значением и, следовательно, у него нет адреса памяти, который вы можете на самом деле взять адрес и привести к указателю на указатель. Сначала вы должны сохранить значение указателя возврата в адресе памяти. Места памяти - это l-значения, и к ним может быть применен оператор адреса. Вот почему ваш второй метод (или метод Dark Falcon) работает, хотя имейте в виду, что возвращаемое значение указателя является временным, что означает, что если вы выполните какие-либо операции над объектом std::string, он может сделать недействительным указатель, так как std::string Объект внутренне управляет памятью своих структур данных. Поэтому то, что вы сохранили значение возвращаемого указателя в ячейке памяти, не означает, что указатель не будет признан недействительным в более позднее время, и в тот момент, когда вы не сможете определиться с выбором.

11 голосов
/ 18 мая 2011

Вы можете получить разумный вызов с помощью вспомогательного класса.Определите этот класс:

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);
7 голосов
/ 18 мая 2011

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);
2 голосов
/ 18 мая 2011

Я только хочу отметить, что указатель, возвращаемый c_str(), действителен только в том случае, если вы не делаете ничего, что требует перераспределения внутреннего буфера std :: string. Это делает недействительным указатель, который вы получили.

Но так как вам действительно требуется **, я бы сделал это:

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

Это должно сработать, если вы не выходите за рамки mychararr.

1 голос
/ 04 апреля 2014

Shader.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);
}

Shader.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
0 голосов
/ 12 сентября 2014

Использование адреса строки и приведение его также работает в одну строку:

glShaderSource(vertexShader, 1, (const char* const*)&vertexSource, NULL);

0 голосов
/ 18 мая 2011

Попробуйте использовать .c_str (), он даст вам символ *, который вы можете использовать, как он работал для вас b4

#include <string>

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