Ответ 1
data.c_str()
возвращает a const char*
, поэтому сделайте следующее:
const char *c_str = data.c_str();
glShaderSource(shader, 1, &c_str, NULL);
У меня есть следующий код:
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
, но, очевидно, это не имеет значения.
data.c_str()
возвращает a const char*
, поэтому сделайте следующее:
const char *c_str = data.c_str();
glShaderSource(shader, 1, &c_str, NULL);
Возвращаемое значение std::string::c_str()
- это значение указателя (т.е. адрес) для статического строкового массива, хранящегося внутри структур данных объекта std::string
. Поскольку возвращаемое значение - это только временное значение r (т.е. Это просто номер, хранящийся в регистре CPU), это не значение l, и поэтому у него нет адреса памяти, который вы можете фактически берут адрес и переводят его в указатель на указатель. Сначала вы должны сохранить возвращаемое значение указателя в адресе памяти. Положения памяти - это l-значения, и к ним может применяться адрес-оператор. Вот почему ваш второй метод (или метод Dark Falcon) работает, хотя имейте в виду, что возвращаемое значение указателя является временным, что означает, что если вы выполняете какие-либо операции с объектом std::string
, это может привести к недействительности указателя, поскольку std::string
объект внутренне управляет памятью своих структур данных. Таким образом, только потому, что вы сохранили значение указателя возврата в ячейке памяти, это не означает, что указатель не будет признан недействительным позднее и в тот момент, когда вы не сможете детерминировать выбор.
Вы можете получить разумный вызов, используя вспомогательный класс. Определите этот класс:
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);
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);
Я хочу только указать, что указатель, возвращаемый c_str()
, действителен только в том случае, если вы не делаете ничего, что требует перераспределения внутреннего буфера std::string. Это приводит к недействительности указателя, который вы получили.
Но так как вам действительно нужен **
, я бы сделал это:
const char* mychararr[1] = {data.c_str()};
glShaderSource(shader, 1, mychararr, NULL);
Это должно работать хорошо, пока вы не покидаете сферу mychararr.
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
Попробуйте использовать .c_str(), он даст вам char *, который вы можете использовать, поскольку он сработал для вас. b4
#include <string>
void ConversionSample ()
{
std::string strTest ("This is a string");
const char* pszConstString = strTest.c_str ();
}
Использование строкового адреса и его литье также работает в одной строке:
glShaderSource(vertexShader, 1, (const char* const*)&vertexSource, NULL);