1

I want to know the feasibility of converting packed homogenous structs (structs with members of same datatype) into arrays by casting them straight to pointers.

I have a packed vec3 struct with members x,y,z that i need to pass as a vec3 uniform to the vertex shader.


typedef struct vec3_t 
{
  float x;
  float y;
  float z;
}__attribute__((packed)) vec3;

int main()
{

/*
boilerplate stuff, window init, shader loading etc.
*/

vec3 v;
v.x=0.0f;
v.y=1.0f;
v.z=0.0f;

GLuint location=glGetUniformLocation(shaderId,uniformName);
glUniform3fv(location,1,(float*)&v);

}

Now I do get a

-Waddress-of-packed-member 

warning when i compile it but when i looked it up, it was mostly about pointers to a member of the struct, not the struct itself, so I didn't find much info for the usecase I was looking for. I know this is potentially unsafe because what undefined behaviour isn't. However I'm having doubts about how unsafe this is. Should i continue using this or should i move to

float[3] 

as 3d vectors if absolutely necessary?

Edit: Referring to the documentation for glUniform3fv, it can be safely assumed that any type with a GL- prefix is a typedef for that same type, eg: GLfloat for float (with some exceptions like GLsizei)

  • You should better use the data types as specified in the documentation of function `glUniform3fv` and avoid casting. A packed structure may contain unaligned members. By casting the address to a different pointer, the function will assume that all elements of the new type are correctly aligned which does not necessarily correspond to the members of the packed structure. This is undefined behavior. Technically it might result in using wrong data with unexpected results or program crash or even seemingly working program. – Bodo Oct 26 '22 at 12:12
  • Contrary to what the question title suggests, your code does not cast a structure to a pointer. I doubt there are many compilers that would accept such a thing. Rather, you are casting a *pointer to* a structure to type `float *`. – John Bollinger Oct 26 '22 at 12:25
  • @Bodo, the doc states that the function takes a location, the number of uniforms and a float array (hence the float pointer cast) respectively. So if the expected argument is a float array and the address of the packed vector is cast to float* i don't think there would be any concern of unaligned struct members. – usrnew xnew Oct 26 '22 at 12:27
  • 2
    "*I know this is potentially unsafe [, but] I'm having doubts about how unsafe*" -- UB is UB. It is unsafe. If you must quantify it, the proper criteria are what is within the power of the program to do (which is mostly of function of where and how it is run, not what is in it), and what is is the impact if it does the worst possible thing. – John Bollinger Oct 26 '22 at 12:31
  • The declaration is `void glUniform3fv(GLint location, GLsizei count, const GLfloat *value);`. The third arg is a pointer to `GLfloat`, probably an array of `GLfloat` values is expected. If `GLfloat` is the same as `float` or not depends on your platform. Your packed structure may or may not have the expected memory layout. In any case it is UB. – Bodo Oct 26 '22 at 12:37
  • @Bodo GLfloat is a typedef for float in this case, I'll add it in the original question. – usrnew xnew Oct 26 '22 at 12:44
  • Why, if the 3rd argument in the `glUniform3fv` function takes a `GLfloat *`, do you choose to cast to `float *`. What are you gaining here? – ryyker Oct 26 '22 at 12:59
  • You should not rely on this `typedef`, and a link to the documentation that guarantees that `GLfloat` is the same as `float` might be helpful. The developers chose to use `GLfloat` for portability reasons. Please [edit] your question and explain why you want to use a structure instead of the expected array. Is it only to get named fields `x`, `y` and `z`? See also https://www.khronos.org/opengl/wiki/OpenGL_Type and https://stackoverflow.com/q/12285502/10622916 and https://stackoverflow.com/a/25524745/10622916 – Bodo Oct 26 '22 at 13:06
  • Honestly, this is a part of a pet project of mine and whether it runs on different architectures is of no relevance to this question.@Bodo yes essentially i want to access components of the vector as x,y and z not array indices. Will check out the links you posted. – usrnew xnew Oct 26 '22 at 13:15
  • No relevance to this question *at the moment. Forgot to add that in my prev comment – usrnew xnew Oct 26 '22 at 13:22
  • @usrnewxnew In that case, you may want to use (or write) a class that stores the elements as an array and has getters and setters for the x, y, z components. Qt's QVector3D does this, for example. – Yun Oct 26 '22 at 13:42
  • @Yun I'm using C so something like getx(vec3* v) would probably be a bit more tedious than I'd like but I'll see how it fares up along with inlining. – usrnew xnew Oct 26 '22 at 14:26
  • Ah, sorry I missed that. Then that would be the alternative indeed, but perhaps simply using array-access (`[i]`) would be more idiomatic C. – Yun Oct 26 '22 at 14:39
  • 1
    You could use preprocessor macros or `enum` values to name the index values corresponding to the coordinate direction. Example: `enum coordIndex { X = 0, Y, Z, MAX }; GLfloat v[MAX]; v[X] = 0.0f;` etc. – Bodo Oct 26 '22 at 16:53
  • `typedef union { struct { float x,y,z; }; float v[3]; } vec3;` ... `vec3 v; glUniform3fv(..., v.v);` – Yakov Galka Oct 27 '22 at 14:47

0 Answers0