How can I safely guarantee that the char * type will be correctly implemented (on any platform) in accordance with the OpenGL specification?

Trying to think about graphical programming using C ++ and OpenGL3 +, I ran into the problem of a bit of specialized understanding of the char type, pointers to it and the potential implicit or explicit conversion to other types of char pointers. I think I managed to find a solution, but I would like to double by asking you to accept this.

Current (October 2014) The main specification of the OpenGL4.5 profile (Table 2.2 in Chapter 2.2 Command Syntax) contains a list of OpenGL data types and explicitly indicates

GL types are not C types. Thus, for example, GL type int is referred to as GLint outside of this document and is not necessarily equivalent to C type int. The implementation must accurately use the number of bits indicated in the table to represent the GL type.

The GLchar type in this table is defined as the bit width type of 8, which is used to represent the characters that make up the string.
To further narrow down what GLchar should provide, we can take a look at the GLSL Specification (OpenGL Shading Language 4.50, July 2014, Chapter 3.1 Character Set and Compilation Steps):

The original character set used for OpenGL shading languages โ€‹โ€‹is Unicode in the UTF-8 encoding scheme.

Now, as implemented in any OpenGL library header that I needed to look for, this is simple

typedef char GLchar;

, , " GL - C", .

, typedefs , .

.

OpenGL, GLSL GLchar, . (, , . , .)

open.gl :

const GLchar* vertexSource =
"#version 150 core\n"
"in vec2 position;"
"void main() {"
"   gl_Position = vec4(position, 0.0, 1.0);"
"}";

:

// Shader macro
#define GLSL(src) "#version 150 core\n" #src

// Vertex shader
const GLchar* vertexShaderSrc = GLSL(
  in vec2 pos;

  void main() {
      gl_Position = vec4(pos, 0.0, 1.0);
  }
);

lazyfoo.net( 30 ) ( ) std::string shaderString, GL:

const GLchar* shaderSource = shaderString.c_str();

, , - , , google - ClockworkCoders , SDK OpenGL, - GLchar*, GLubyte* - :

GLchar** ShaderSource;
unsigned long len;
ifstream file;
// . . .
len = getFileLength(file);
// . . .
*ShaderSource = (GLubyte*) new char[len+1];

++ . g++ , -fpermissive. , , GLubyte - , , typedef unsigned char, , char. , - . ++, char* signed unsigned char*, - . , :

, , OpenGL typedef . . , GL .

OpenGL - - - , GLchar typedef char, , . , , , , .

, : wiki opengl.org Shader Compilation, ..:

std::string vertexSource = //Get source code for vertex shader.
// . . .
const GLchar *source = (const GLchar *)vertexSource.c_str();

- const GLchar* . , , , , OpenGL (): 8, UTF-8.

, GLchar2, , :

// GLchar2.h - a char type of 1 byte length

#include <iostream>
#include <locale> // handle whitespaces

class GLchar2 {
  char element; // value of the GLchar2 variable
public:
  // default constructor
  GLchar2 () {}
  // user defined conversion from char to GLchar2
  GLchar2 (char element) : element(element) {}
  // copy constructor
  GLchar2 (const GLchar2& c) : element(c.element) {}
  // destructor
  ~GLchar2 () {}
  // assignment operator
  GLchar2& operator= (const GLchar2& c) {element = c; return *this;}
  // user defined conversion to integral c++ type char
  operator char () const {return element;}
};

// overloading the output operator to correctly handle GLchar2
// due to implicit conversion of GLchar2 to char, implementation is unnecessary
//std::ostream& operator<< (std::ostream& o, const GLchar2 character) {
//  char out = character;
//  return o << out;
//}

// overloading the output operator to correctly handle GLchar2*
std::ostream& operator<< (std::ostream& o, const GLchar2* output_string) {
  for (const GLchar2* string_it = output_string; *string_it != '\0'; ++string_it) {
    o << *string_it;
  }
  return o;
}

// overloading the input operator to correctly handle GLchar2
std::istream& operator>> (std::istream& i, GLchar2& input_char) {
  char in;
  if (i >> in) input_char = in; // this is where the magic happens
  return i;
}

// overloading the input operator to correctly handle GLchar2*
std::istream& operator>> (std::istream& i, GLchar2* input_string) {
  GLchar2* string_it;
  int width = i.width();
  std::locale loc;
  while (std::isspace((char)i.peek(),loc)) i.ignore(); // ignore leading whitespaces
  for (string_it = input_string; (((i.width() == 0 || --width > 0) && !std::isspace((char)i.peek(),loc)) && i >> *string_it); ++string_it);
  *string_it = '\0'; // terminate with null character
  i.width(0); // reset width of i
  return i;
}

, , , GLchar2 c-string. , , char GLchar2 ( ). char GLchar2 .

, GLchar , . typedef char GLchar1;, , :

// program: test_GLchar.cpp - testing implementation of GLchar

#include <iostream>
#include <fstream>
#include <locale> // handle whitespaces
#include "GLchar2.h"

typedef char GLchar1;

int main () {
  // byte size comparison
  std::cout << "GLchar1 has a size of " << sizeof(GLchar1) << " byte.\n"; // 1
  std::cout << "GLchar2 has a size of " << sizeof(GLchar2) << " byte.\n"; // 1
  // char constructor
  const GLchar1 test_char1 = 'o';
  const GLchar2 test_char2 = 't';
  // default constructor
  GLchar2 test_char3;
  // char conversion
  test_char3 = '3';
  // assignment operator
  GLchar2 test_char4;
  GLchar2 test_char5;
  test_char5 = test_char4 = 65; // ASCII value 'A'
  // copy constructor
  GLchar2 test_char6 = test_char5;
  // pointer conversion
  const GLchar1* test_string1 = "test string one"; // compiles
  //const GLchar1* test_string1 = (const GLchar1*)"test string one"; // compiles
  //const GLchar2* test_string2 = "test string two"; // does *not* compile!
  const GLchar2* test_string2 = (const GLchar2*)"test string two"; // compiles

  std::cout << "A test character of type GLchar1: " << test_char1 << ".\n"; // o
  std::cout << "A test character of type GLchar2: " << test_char2 << ".\n"; // t
  std::cout << "A test character of type GLchar2: " << test_char3 << ".\n"; // 3
  std::cout << "A test character of type GLchar2: " << test_char4 << ".\n"; // A
  std::cout << "A test character of type GLchar2: " << test_char5 << ".\n"; // A
  std::cout << "A test character of type GLchar2: " << test_char6 << ".\n"; // A

  std::cout << "A test string of type GLchar1: " << test_string1 << ".\n";
  // OUT: A test string of type GLchar1: test string one.\n
  std::cout << "A test string of type GLchar2: " << test_string2 << ".\n";
  // OUT: A test string of type GLchar2: test string two.\n

  // input operator comparison
  // test_input_file.vert has the content
  //  If you can read this,
  //  you can read this.
  // (one whitespace before each line to test implementation)
  GLchar1* test_string3;
  GLchar2* test_string4;
  GLchar1* test_string5;
  GLchar2* test_string6;
  // read character by character
  std::ifstream test_file("test_input_file.vert");
  if (test_file) {
    test_file.seekg(0, test_file.end);
    int length = test_file.tellg();
    test_file.seekg(0, test_file.beg);

    test_string3 = new GLchar1[length+1];
    GLchar1* test_it = test_string3;
    std::locale loc;
    while (test_file >> *test_it) {
      ++test_it;
      while (std::isspace((char)test_file.peek(),loc)) {
        *test_it = test_file.peek(); // add whitespaces
        test_file.ignore();
        ++test_it;
      }
    }
    *test_it = '\0';
    std::cout << test_string3 << "\n";
    // OUT: If you can read this,\n you can read this.\n
    std::cout << length << " " <<test_it - test_string3 << "\n";
    // OUT: 42 41\n
    delete[] test_string3;
    test_file.close();
  }
  std::ifstream test_file2("test_input_file.vert");
  if (test_file2) {
    test_file2.seekg(0, test_file2.end);
    int length = test_file2.tellg();
    test_file2.seekg(0, test_file2.beg);

    test_string4 = new GLchar2[length+1];
    GLchar2* test_it = test_string4;
    std::locale loc;
    while (test_file2 >> *test_it) {
      ++test_it;
      while (std::isspace((char)test_file2.peek(),loc)) {
        *test_it = test_file2.peek(); // add whitespaces
        test_file2.ignore();
        ++test_it;
      }
    }
    *test_it = '\0';
    std::cout << test_string4 << "\n";
    // OUT: If you can read this,\n you can read this.\n
    std::cout << length << " " << test_it - test_string4 << "\n";
    // OUT: 42 41\n
    delete[] test_string4;
    test_file2.close();
  }
  // read a word (until delimiter whitespace)
  test_file.open("test_input_file.vert");
  if (test_file) {
    test_file.seekg(0, test_file.end);
    int length = test_file.tellg();
    test_file.seekg(0, test_file.beg);

    test_string5 = new GLchar1[length+1];
    //test_file.width(2);
    test_file >> test_string5;
    std::cout << test_string5 << "\n";
    // OUT: If\n
    delete[] test_string5;
    test_file.close();
  }
  test_file2.open("test_input_file.vert");
  if (test_file2) {
    test_file2.seekg(0, test_file2.end);
    int length = test_file2.tellg();
    test_file2.seekg(0, test_file2.beg);

    test_string6 = new GLchar2[length+1];
    //test_file2.width(2);
    test_file2 >> test_string6;
    std::cout << test_string6 << "\n";
    // OUT: If\n
    delete[] test_string6;
    test_file2.close();
  }
  // read word by word
  test_file.open("test_input_file.vert");
  if (test_file) {
    test_file.seekg(0, test_file.end);
    int length = test_file.tellg();
    test_file.seekg(0, test_file.beg);

    test_string5 = new GLchar1[length+1];
    GLchar1* test_it = test_string5;
    std::locale loc;
    while (test_file >> test_it) {
      while (*test_it != '\0') ++test_it; // test_it points to null character
      while (std::isspace((char)test_file.peek(),loc)) {
        *test_it = test_file.peek(); // add whitespaces
        test_file.ignore();
        ++test_it;
      }
    }
    std::cout << test_string5 << "\n";
    // OUT: If you can read this,\n you can read this.\n
    delete[] test_string5;
    test_file.close();
  }
  test_file2.open("test_input_file.vert");
  if (test_file2) {
    test_file2.seekg(0, test_file2.end);
    int length = test_file2.tellg();
    test_file2.seekg(0, test_file2.beg);

    test_string6 = new GLchar2[length+1];
    GLchar2* test_it = test_string6;
    std::locale loc;
    while (test_file2 >> test_it) {
      while (*test_it != '\0') ++test_it; // test_it points to null character
      while (std::isspace((char)test_file2.peek(), loc)) {
        *test_it = test_file2.peek(); // add whitespaces
        test_file2.ignore();
        ++test_it;
      }
    }
    std::cout << test_string6 << "\n";
    // OUT: If you can read this,\n you can read this.\n
    delete[] test_string6;
    test_file2.close();
  }
  // read whole file with std::istream::getline
  test_file.open("test_input_file.vert");
  if (test_file) {
    test_file.seekg(0, test_file.end);
    int length = test_file.tellg();
    test_file.seekg(0, test_file.beg);

    test_string5 = new GLchar1[length+1];
    std::locale loc;
    while (std::isspace((char)test_file.peek(),loc)) test_file.ignore(); // ignore leading whitespaces
    test_file.getline(test_string5, length, '\0');
    std::cout << test_string5  << "\n";
    // OUT: If you can read this,\n you can read this.\n
    delete[] test_string5;
    test_file.close();
  }
  // no way to do this for a string of GLchar2 as far as I can see
  // the getline function that returns c-strings rather than std::string is
  // a member of istream and expects to return *this, so overloading is a no go
  // however, this works as above:

  // read whole file with std::getline
  test_file.open("test_input_file.vert");
  if (test_file) {
    std::locale loc;
    while (std::isspace((char)test_file.peek(),loc)) test_file.ignore(); // ignore leading whitespaces
    std::string test_stdstring1;
    std::getline(test_file, test_stdstring1, '\0');
    test_string5 = (GLchar1*) test_stdstring1.c_str();
    std::cout << test_string5 << "\n";
    // OUT: If you can read this,\n you can read this.\n
    test_file.close();
  }

  test_file2.open("test_input_file.vert");
  if (test_file2) {
    std::locale loc;
    while (std::isspace((char)test_file2.peek(),loc)) test_file2.ignore(); // ignore leading whitespaces
    std::string test_stdstring2;
    std::getline(test_file2, test_stdstring2, '\0');
    test_string6 = (GLchar2*) test_stdstring2.c_str();
    std::cout << test_string6 << "\n";
    // OUT: If you can read this,\n you can read this.\n
    test_file.close();
  }

  return 0;
}

, , GLchar , ++:

  • char GLchar (, ).

    const GLchar* sourceCode = (const GLchar*)"some code";

    std::string sourceString = std::string("some code"); // can be from a file GLchar* sourceCode = (GLchar*) sourceString.c_str();

  • GLchar.

, , . , OpenGL , . , , - , , , char.

, , c-.

: , , OpenGL, , "" "", ( ) ?

, stackoverflow, , , , .

, , ( ). , , OpenGL , .

+4
2

@datenwolf:

CHAR_BIT: C CHAR_BIT >= 8, char - C, OpenGL - 8-. , OpenGL CHAR_BIT != 8...,

... GL API , 2.2.

OpenGL 4.5.

GLubyte* char*, AFAIK C ++. char* ,

int x;
istream &is = ...;
is.read((char*)&x, sizeof(x));

. sizeof(char) == sizeof(GLchar) == 1 OpenGL C, GLchar char.

, " GL C", , OpenGL , "float" "int" "GL", , , , , () C. , OpenGL "int" C "long" C. , C, OpenGL ( C ).

, , OpenGL, - , "" "" - ( )

, -, , OpenGL . OpenGL , C , , const GLchar *str = "hello world". , C-, ++, , 2.2.

Edit:

CHAR_BIT > 8. . , . DSP. POSIX CHAR_BIT == 8.

basic_strings iostreams , , . , , . , , , codecvt .., . , char.

+2

OpenGL

" GL C"

, OpenGL , , , . , C. , OpenGL API OpenGL.

OpenGL , GLchar - 8 ( ). , . , , GLchar 8- , . , static assert CHAR_BIT == 8, , .

OpenGL ( BTW) , ABI. gl.h

#include <stdint.h>
typedef int8_t GLchar;

int8_t, , ,

typedef signed char int8_t;

.

- OpenGL - - - , GLchar typedef char, ,

OpenGL API C ABI. GLchar - 8 , API , . , OpenGL GLchar, , OpenGL-over-network, GLX.

Update

, . C - C int, char ( ) , char C . .

2

, - C, ABI CHAR_BIT != 8 OpenGL - , , C CHAR_BIT != 8 . int short? ! char? .

3

++, glstring std::basic_string , , GLchar. ABI GLchar signed char , , C.

+3

Source: https://habr.com/ru/post/1569837/


All Articles