Thread: C Typecasting Help

  1. #1
    Registered User
    Join Date
    May 2009
    Location
    Look in your attic, I am there...
    Posts
    92

    C Typecasting Help

    I have no idea how c is typecasting a single 32 bit Integer into a struct with multiple elements... Any help explaining would be greatly appreciated

    Declarations
    Code:
    struct md2_glcmd_t
    {
      float s;
      float t;
      int index;
    };
    struct md2_model_t
    {
      struct md2_header_t header;
      struct md2_skin_t *skins;
      struct md2_texCoord_t *texcoords;
      struct md2_triangle_t *triangles;
      struct md2_frame_t *frames;
      int *glcmds;
      GLuint tex_id;
    };
    Reading
    Code:
    ReadMD2Model (const char *filename, struct md2_model_t *mdl)
    {
      . . .
      fseek (fp, mdl->header.offset_glcmds, SEEK_SET);
      fread (mdl->glcmds, sizeof (int), mdl->header.num_glcmds, fp);
      . . .
    }
    Another example of the typecasting used...
    Code:
    . . .
    int i, *pglcmds;
    packet = (struct md2_glcmd_t *)pglcmds;
    . . .

  2. #2
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    There is no cast in the “Reading” example. What it's doing is reading a certain number of ints (that number being mdl->header.num_glcmds) and storing them at the value pointed to by mdl->glcmds, which happens to be an int pointer. There is nothing strange going on there.

    The second example does contain a cast, and it really doesn't make sense. While you're allowed to convert from one object pointer to another, the result is not portable, and it's generally the wrong thing to do. I'm not sure what the code expects is going to happen. I assume pglcmds is a pointer to some integral data, since that's what its type implies. However, it's being interpreted as a pointer to a struct which contains two floats and an int. Now, it's possible that it really does point to such a struct, but then using the type int* is wrong.

    Which is, basically, the upshot: the code is wrong. I suppose there might be a reason it's done this way, but without seeing more code, it's impossible to say.

  3. #3
    Registered User
    Join Date
    May 2009
    Location
    Look in your attic, I am there...
    Posts
    92
    However, it's being interpreted as a pointer to a struct which contains two floats and an int.
    Yes, but how does C do that conversion?

    Oh and here is the full code..
    Code:
    void
    RenderFrameItpWithGLCmds (int n, float interp, const struct md2_model_t *mdl)
    {
      int i, *pglcmds;
      vec3_t v_curr, v_next, v, norm;
      float *n_curr, *n_next;
      struct md2_frame_t *pframe1, *pframe2;
      struct md2_vertex_t *pvert1, *pvert2;
      struct md2_glcmd_t *packet;
    
      /* Check if n is in a valid range */
      if ((n < 0) || (n > mdl->header.num_frames - 1))
        return;
    
      /* Enable model's texture */
      glBindTexture (GL_TEXTURE_2D, mdl->tex_id);
    
      /* pglcmds points at the start of the command list */
      pglcmds = mdl->glcmds;
    
      /* Draw the model */
      while ((i = *(pglcmds++)) != 0)
        {
          if (i < 0)
    	{
    	  glBegin (GL_TRIANGLE_FAN);
    	  i = -i;
    	}
          else
    	{
    	  glBegin (GL_TRIANGLE_STRIP);
    	}
    
          /* Draw each vertex of this group */
          for (/* Nothing */; i > 0; --i, pglcmds += 3)
    	{
    	  packet = (struct md2_glcmd_t *)pglcmds;
    	  pframe1 = &mdl->frames[n];
    	  pframe2 = &mdl->frames[n + 1];
    	  pvert1 = &pframe1->verts[packet->index];
    	  pvert2 = &pframe2->verts[packet->index];
    
    	  /* Pass texture coordinates to OpenGL */
    	  glTexCoord2f (packet->s, packet->t);
    
    	  /* Interpolate normals */
    	  n_curr = anorms_table[pvert1->normalIndex];
    	  n_next = anorms_table[pvert2->normalIndex];
    
    	  norm[0] = n_curr[0] + interp * (n_next[0] - n_curr[0]);
    	  norm[1] = n_curr[1] + interp * (n_next[1] - n_curr[1]);
    	  norm[2] = n_curr[2] + interp * (n_next[2] - n_curr[2]);
    
    	  glNormal3fv (norm);
    
    	  /* Interpolate vertices */
    	  v_curr[0] = pframe1->scale[0] * pvert1->v[0] + pframe1->translate[0];
    	  v_curr[1] = pframe1->scale[1] * pvert1->v[1] + pframe1->translate[1];
    	  v_curr[2] = pframe1->scale[2] * pvert1->v[2] + pframe1->translate[2];
    
    	  v_next[0] = pframe2->scale[0] * pvert2->v[0] + pframe2->translate[0];
    	  v_next[1] = pframe2->scale[1] * pvert2->v[1] + pframe2->translate[1];
    	  v_next[2] = pframe2->scale[2] * pvert2->v[2] + pframe2->translate[2];
    
    	  v[0] = v_curr[0] + interp * (v_next[0] - v_curr[0]);
    	  v[1] = v_curr[1] + interp * (v_next[1] - v_curr[1]);
    	  v[2] = v_curr[2] + interp * (v_next[2] - v_curr[2]);
    
    	  glVertex3fv (v);
    	}
    
          glEnd ();
        }

  4. #4
    Registered User
    Join Date
    Mar 2010
    Posts
    583
    Quote Originally Posted by 127.0.0.1 View Post
    Yes, but how does C do that conversion?
    Nothing is "converted" really. A pointer is just an address -- there is some data at that address (hopefully). The type of the pointer determines how the data is interpreted, but the underlying representation stays the same.

    Code:
    struct md2_glcmd_t
    {
      float s;
      float t;
      int index;
    };
    
    
    int i, *pglcmds;
      <.... pglcmds set to some address.... >
    packet = (struct md2_glcmd_t *)pglcmds;

    Let's say that pglcmds gets set to 0x10000000 - an address, the value of the pointer.
    Then after the cast:

    Code:
    float blah = packet->s;   /* accesses memory at 0x10000000 and treats it like a float -- i.e. it can be assigned to floats without a cast, the bitpattern is interpreted as two's complement.... */
    int blah2 = packet->t;    /* Same, but accesses memory one sizeof(float) further up, probably 0x10000004 */
    I'd be unsurprised to see code like this mapping a structure onto some memory mapped peripheral (for example). This looks like it might be a frame buffer? In which case the data might have been loaded/stored into that memory without any particular interpretation applied at the time (i.e. just a byte stream). Maybe not, complete guess.

  5. #5
    Registered User
    Join Date
    May 2009
    Location
    Look in your attic, I am there...
    Posts
    92
    Wow, thanks for the help cas and detailed answer angel. I think I have it now

    1. the number of opengl commands is read num_glcmds
    2. one integer per num_glcmds is read and pointed to with mdl->glcmds
    3. the integer pointer pglcmds is set equal to mdl->glcmds
    4. an md2_glcmd_t variable packet is set equal to (struct md2_glcmd_t *)pglcmds. This leaves the first value in packet a float, the second a float, and the third an integer.
    5. pglcmds is then incremented to move three bytes over via the for(/* Nothing */; i > 0; --i, pglcmds += 3)
    6. #4 and #5 are repeated until the constraints are met.

  6. #6
    Registered User
    Join Date
    Mar 2010
    Posts
    583
    Quote Originally Posted by 127.0.0.1 View Post
    Wow, thanks for the help cas and detailed answer angel. I think I have it now

    1. the number of opengl commands is read num_glcmds
    2. one integer per num_glcmds is read and pointed to with mdl->glcmds
    3. the integer pointer pglcmds is set equal to mdl->glcmds
    4. an md2_glcmd_t variable packet is set equal to (struct md2_glcmd_t *)pglcmds. This leaves the first value in packet a float, the second a float, and the third an integer.
    Sounds right

    5. pglcmds is then incremented to move three bytes over via the for(/* Nothing */; i > 0; --i, pglcmds += 3)
    Pointer arithmetic adds in increments of the size of the pointer -- so actually it adds 12 bytes. Which makes sense, since the struct is 12 bytes, it's processing something that may have originally looked like an array of structs.

    This is a pretty bad idea -- relying on sizeof(int*) * 3 == float + float + int, as it is not portable if any of these sizes change...

  7. #7
    Registered User
    Join Date
    May 2009
    Location
    Look in your attic, I am there...
    Posts
    92
    I don't see why they didn't divide num_glcmds by 3 and just read the Record/Struct outright instead of doing unnecessary operations -- C programmers for you

    Again, I can't tell you how much I appreciate the help. I am an Ada95 programmer so some of this crazy typecasting catches me off guard.

  8. #8
    Registered User
    Join Date
    Mar 2010
    Posts
    583
    Quote Originally Posted by 127.0.0.1 View Post
    I don't see why they didn't divide num_glcmds by 3 and just read the Record/Struct outright instead of doing unnecessary operations -- C programmers for you
    Oi, C programmers good!
    This bit of pointer arithmetic might be a "I'm cleverer than the compiler" left over from when hand optimising high level languages was a worthwhile task. I doubt it though - suspect it's just style preference.

    Again, I can't tell you how much I appreciate the help. I am an Ada95 programmer so some of this crazy typecasting catches me off guard.
    No problem :-) I used Ada95 briefly for a project at university, and I remember its rigid type structure. As I recall it took me a week to get anything to compile each to their own!

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Pointer Arithmetic and Typecasting
    By pobri19 in forum C Programming
    Replies: 2
    Last Post: 03-19-2009, 11:06 PM
  2. recv() typecasting error
    By jmd15 in forum Networking/Device Communication
    Replies: 7
    Last Post: 05-19-2006, 03:32 PM
  3. c and c++ style typecasting confusion
    By vaibhav in forum C++ Programming
    Replies: 14
    Last Post: 08-30-2005, 07:29 AM
  4. typecasting
    By sreetvert83 in forum C++ Programming
    Replies: 7
    Last Post: 07-22-2005, 01:55 PM
  5. typecasting
    By JaWiB in forum C++ Programming
    Replies: 14
    Last Post: 06-01-2003, 10:42 PM