Jump to content


[C++] Arrays and contiguity


27 replies to this topic

#21 JarkkoL

    Senior Member

  • Members
  • PipPipPipPip
  • 475 posts

Posted 11 November 2009 - 07:46 PM

SyntaxError said:

In my view writing something that moves pointers between structures in this way is kind of crazy. Change or add one more field and it fails even in everyday VC++.
General way compilers pad structures is by adding bytes after each member so that the next member aligns properly, or after the last member so that the next instance of the enclosing type aligns properly. What OP is basically asking is if sizeof(Vec3)==sizeof(float)*3, which in the particular implementation of Vec3 is true in practice, particularly that it's a POD type, even though not strictly guaranteed by the C++ standard.

SyntaxError said:

I would hope that not too many programmers are relying on this behavior
Well, if you are programming e.g. for D3D you probably are (: A common use case where knowing the memory layout of a type is useful is when you pass e.g. vertex data to D3D, which returns you void* upon Lock(), which you cast to the structure that defines the vertex. Sure you could pass all vertex atributes by using float*, but it's just much more convenient to use struct and rely on the memory layout, because it just works in practice.

#22 SyntaxError

    Valued Member

  • Members
  • PipPipPip
  • 139 posts

Posted 11 November 2009 - 07:56 PM

rouncer said:

So i gather counting the amount of variables in your structure in no way dictates final memory usage?

Check this out:


#include "stdafx.h"

#include <stdio.h>


struct Vec3 { double x; float y; float z; };

struct Vec4 { float y; double x; float z; };


int main()

{

   printf("sizeof(Vec3)=%d\n",sizeof(Vec3));

   printf("sizeof(Vec4)=%d\n",sizeof(Vec4));

   return 0 ;

}


Results:

sizeof(Vec3)=16
sizeof(Vec4)=24

Now the only difference is the order that members are declared in the structure. So in short the answer is no. However for VC++ you can usually figure it out based on the alignment requirements but then a different complier might rearrange your members to save space. Just don't rely on it. Over the years I have dealt with stuff like this numerous times when porting code. Alignment issues can cause a lot of problems when you start taking liberties. This isn’t some theoretical C++ nitpick. It does happen all the time so you should be careful.

#23 .oisyn

    DevMaster Staff

  • Moderators
  • 1842 posts

Posted 11 November 2009 - 08:30 PM

SyntaxError said:

but then a different complier might rearrange your members to save space.
Actually, no, a conforming compiler may not rearrange them. It is defined that every member of a class or struct within the same public/protected/private section has an address that is greater than the one of the previous member. In your example, a compiler may only rearrange x, y and z if you put a public: in front of each declaration. Nevertheless, I've seen compilers do it anyway (the ARM compiler for the Gameboy Advance. It even rearranged bitfields, which was very annoying as I was trying to define structs that were compatible with the hardware layout of things like sprites and such ;))

Of course, as far as padding is concerned all bets are off. But the standard guarantees that offsetof(Vec3, x) < offsetof(Vec3, y).
C++ addict
-
Currently working on: the 3D engine for Tomb Raider.

#24 JarkkoL

    Senior Member

  • Members
  • PipPipPipPip
  • 475 posts

Posted 11 November 2009 - 08:30 PM

SyntaxError said:

...a different complier might rearrange your members to save space.
Actually, to my knowledge it's not allowed for a C++ standard conforming compiler to rearrange the order of a POD member variables at least. Which compiler are you referring to?

Edit: duh, you beat me .oisyn (:

#25 poita

    Senior Member

  • Members
  • PipPipPipPip
  • 322 posts

Posted 12 November 2009 - 12:07 AM

SyntaxError said:

Possibly the OP could give us a more detailed description of the actual problem being solved.

As I said in the original post, I want to be able to store vertex position data in a std::vector<Vector3> and then pass in the address of the first element into glVertexPointer.

If you aren't familiar, glVertexPointer accepts a float* -- an array of vertex coordinates, laid out such that v[0] = a.x, v[1] = a.y, v[2] = a.z, v[3] = b.x, and so on...

It's not very convenient to work with vectors in this componentwise manner, hence why I want to store them as an array of Vector3's. Also, it would be highly inconvenient if I can to convert my Vector3's into the array of floats every frame (not just inconvenient, but incredibly slow).

I could write a VertexBuffer object that stores them as an array of floats and converts individual triples into Vector3's upon request -- essentially giving it the interface of a std::vector<Vector3>, but it's still inconvenient, and without good inlining, could be slow.

#26 Reedbeta

    DevMaster Staff

  • Administrators
  • 5310 posts
  • LocationSanta Clara, CA

Posted 12 November 2009 - 12:54 AM

Well, I think it's been established that you can store them as an array of Vector3s and that will be 98% fine - especially if you assert that sizeof(Vector3) == 3 * sizeof(float), so you will get an alert if for some reason that ever isn't true.
reedbeta.com - developer blog, OpenGL demos, and other projects

#27 .oisyn

    DevMaster Staff

  • Moderators
  • 1842 posts

Posted 12 November 2009 - 01:07 AM

You could use BOOST_STATIC_ASSERT or C++0x's static_assert (included in VS 2010 and GCC 4.3). If you do not want to use boost and have a portable compile-time assert (which allows you to catch the error earlier) you could do something like:
char c[sizeof(Vec3) == 3*sizeof(float) ? 1 : -1];

C++ addict
-
Currently working on: the 3D engine for Tomb Raider.

#28 SyntaxError

    Valued Member

  • Members
  • PipPipPip
  • 139 posts

Posted 12 November 2009 - 08:56 AM

JarkkoL said:

Actually, to my knowledge it's not allowed for a C++ standard conforming compiler to rearrange the order of a POD member variables at least. Which compiler are you referring to?

You guys are probably right. I do remember something about the compiler being able to rearrange members but it might have been in an older standard or before the standard specified it. I don't really follow the standards in detail.

In any case, in general you still can't count on data being contiguous. However if your structure doesn't change and this is really for DirectX you aren't portable anyway so who cares.

Edit: Oh sorry, it's for openGL so disregard what I wrote, I'm up too late. I guess you do have to worry about it. In any case I've seen machines that like to align everything to double so it might be a problem there, but they are probably few and far between. Also glVertexPointer appears to have a stride parameter so I would think you could just take sizeof() and pass it in.





1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users