2011-05-18 103 views
25

我有以下代碼:如何將std :: string傳遞給glShaderSource?

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但顯然沒有區別。

+4

看一看該函數的文檔。必須有一個原因,它需要一個指針指針。據推測,這是一個輸出參數,函數_writes_是一個'char *'給解引用的char **。在這種情況下,您需要傳遞一個實際指針的地址,而不是由'std :: string :: c_str()'返回的臨時文件。 – sbi 2011-05-18 16:12:00

+1

@sbi:它不是一個輸出參數,它期待着一串c字符串。 – 2011-05-18 16:15:33

+1

@Benjamin:啊,是的,我忘了這種可能性。 – sbi 2011-05-18 16:22:17

回答

42

data.c_str()返回const char*,所以這樣做:

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

是否有可能從它中刪除變量聲明並將其設置爲我稱之爲函數的那一行? – Rookie 2011-05-18 16:02:58

+0

不,請參閱上面的答案。 – Jason 2011-05-18 16:05:38

+1

@Rookie - 聲明,但不初始化,'c_str'某處:'const char * c_str;'。然後,在使用的時候,試試這個:'glShaderSource(shader,1,&(c_str = data.c_str()),NULL);' – 2011-05-18 16:08:28

14

std::string::c_str()返回值是一個指針值(即,地址)的靜態字符串數組std::string對象的數據結構內保持。由於返回只是一個臨時的r值(即它只是一個存儲在CPU寄存器中的數字),它不是一個l值,因此它沒有一個存儲器地址,您可以實際佔用地址並轉換爲指針指針。您首先必須將返回指針值保存在內存地址中。內存位置是l值,並且可以將運算符地址應用於它們。因此,這就是爲什麼你的第二種方法(或Dark Falcon的方法)可以工作,但請記住,返回的指針值是臨時值,這意味着如果您對std::string對象執行任何操作,則可能會使指針無效,因爲std::string對象內部管理其數據結構的內存。所以,僅僅因爲你已經將返回指針值保存在內存位置中,並不意味着指針在稍後的時間不會失效,並且在某個時刻你可能無法確定性地選擇它。

+0

c_str()返回值可以分配給l值 – CharlesB 2011-05-18 15:58:30

+2

@ CharlesB:是的,可以將返回值分配給l值,但返回值本身不是l值,因此您無法應用地址-of運算符返回'std :: string :: c_str()'。 – Jason 2011-05-18 16:02:43

+0

好的,但你的解釋有點不切實際,你不需要這些知識來解決OP問題 – CharlesB 2011-05-18 16:21:27

0

嘗試使用.c_str()它給你一個char *,因爲它爲你工作B4

#include <string> 

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

我只是想指出的是您可以使用由c_str()返回的指針是唯一爲有效只要你不做任何需要重新分配std :: string的內部緩衝區的東西。這使得你得到的指針無效。

但因爲你真的需要一個**我這樣做:

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

很好,只要你不離開mychararr的範圍應工作。

+0

我不認爲初始化編譯(在C++ 03中)。 – sbi 2011-05-18 16:09:09

+0

@sbi:海灣合作委員會很滿意這樣的事情,但我認爲你是對的,它是非標準的。 – 2011-06-20 06:19:05

+0

@Tony:我認爲這是標準的,但C++ 11標準尚未發佈。 – sbi 2011-06-20 06:33:31

7

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

'+ 1'實際查看功能文檔! – sbi 2011-05-18 16:21:35

+0

@sbi和@mister,將字符串拆分成這樣的行是什麼意思?當所有數據都在數組的第一個項目中時,它工作正常。 – Rookie 2011-05-18 18:29:02

+0

@Rookie:如果你想傳遞一個多於一個字符串的數組,這就是你想要的。既然你只想傳遞一個字符串,我想它不適用於你。 – sbi 2011-05-19 09:57:16

11

您可以通過使用助手類來獲得一個看起來很合理的調用。這個類定義:

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); 
+0

我用過這個。我有多個字符串進行轉換,我可以將實現代碼放在一起,並將所有內容都放在一行中。完善。 – GCon 2013-11-16 23:44:36

1

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

請評論您的代碼 – 2014-04-04 08:33:59

+0

大+1,回零,螺絲評論,這是好東西,感謝發貼。 – 2017-02-17 08:17:26

-2

使用字符串的地址S和鑄造它也可以在同一行:

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

+0

但導致未定義的行爲。事實上,它幾乎不會工作。 – Ruslan 2016-08-22 10:33:10

相關問題