web-dev-qa-db-fra.com

Comment passer une ficelle STD :: String to Glshadersource?

J'ai le code suivant:

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

Mais cela fait battre mon programme. Comment puis-je convertir std::string dans const char **? J'ai aussi essayé (const char **)& Mais cela dit "nécessite une valeur L" que je ne comprends pas. Cela fonctionne bien lorsque j'utilise ce code:

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

Mais je ne peux pas faire fonctionner directement d'un std::string. Je pourrais allouer un nouveau tableau char pour cela, mais ce n'est pas un bon code.

J'ai aussi essayé avec const GLchar Mais évidemment, cela ne fait aucune différence.

28
Rookie

data.c_str() retourne un const char*, alors faites ceci:

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

La valeur de retour de std::string::c_str() est une valeur de pointeur (c'est-à-dire une adresse) à une matrice de chaîne statique tenue à l'intérieur des structures de données du std::string objet. Depuis le retour valeur est juste une valeur R temporaire (c'est-à-dire qu'il s'agit simplement d'un nombre stocké dans un registre CPU), il n'est pas une valeur L et il n'a donc pas d'adresse mémoire que vous pouvez. Emportez effectivement l'adresse et jeté à un pointeur à pointeur. Vous devez d'abord enregistrer la valeur du pointeur de retour dans une adresse mémoire. Les emplacements de mémoire sont des valeurs L et peuvent avoir l'adresse de l'opérateur qui leur est appliquée. C'est donc la raison pour laquelle votre deuxième méthode (ou votre méthode de Falcon sombre) fonctionne, bien que gardez à l'esprit que la valeur du pointeur renvoyée est temporaire, ce qui signifie que si vous effectuez des opérations sur le std::string objet, cela pourrait invalider le pointeur depuis le std::string Objet gère en interne la mémoire de ses structures de données. Donc, simplement parce que vous avez sauvegardé la valeur du pointeur de retour dans un emplacement de mémoire ne signifie pas que le pointeur ne sera pas invalidé à un moment donné, et à un point que vous ne pouvez pas être capable de choisir de manière déterministe.

14
Jason

Vous pouvez obtenir un appel à la recherche raisonnable en utilisant une classe d'assistance. Définir cette classe:

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

Ensuite, lorsque vous devez appeler glShaderSource, faites-le de cette façon:

glShaderSource(shader, 1, StringHelper(data), NULL);
11
Robᵩ

glShaderSource Signature est, selon Glshadersource Doc :

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

string "Spécifie une matrice de pointeurs vers des chaînes contenant le code source à charger dans le shader". Ce que vous essayez de passer est un pointeur sur une chaîne terminée NULL (c'est-à-dire un pointeur à un const char*).

Malheureusement, je ne suis pas familier avec glShaderSource, mais je peux deviner que ce n'est pas attendu un pointeur de "certains coder" mais quelque chose comme ça à la place:

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

De - OpenGL-Redbook , vous pouvez lire un exemple (je l'ai raccourci pour but):

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

Je veux seulement souligner que le pointeur renvoyé par c_str() n'est valable que si vous ne faites rien qui nécessite une réaffectation du tampon interne de STD :: String. Cela invalide le pointeur que vous avez obtenu.

Mais puisque tu as vraiment besoin d'un ** je ferais cela:

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

Cela devrait fonctionner bien tant que vous ne quittez pas la portée de MycharRarr.

2
RedX

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
1
Imagine Breaker