First of all I apologize if the title is a bit vague, I couldn't phrase my question to fit in the given space.

So given you have an array of floats that you want to cast as a pointer to a struct containing only floats, assuming the array size is not an issue, can this ever backfire on a given architecture (mobile, windows, mac, etc), compilers (VS's compiler, g++, etc) or implementation (constructor, methods, virtuals methods, etc)?

In my case I only have two constructors and I want to make sure when I port my code to other platforms, things don't blow up.

Also, is there something that can tell the compiler if I have the members: float a, float b, float c, that I want them arranged in that order and not to mix them in memory?

Recommended Answers

All 3 Replies

An array is guaranteed to use contiguous memory (i.e. no gaps between the elements). A struct has no such guarantee; the compiler can choose to put padding between the members for ease of memory access. https://en.wikipedia.org/wiki/Data_structure_alignment#Typical_alignment_of_C_structs_on_x86

As it happens, typically a float is the right size for memory alignment and a struct made of just float will be contiguous, but there are no guarantees on that. You can ask the compiler not to use padding, if it provides that facility. There are performace penalties; the compiler pads structs for a reason, and I wouldn't like to assume that all compilers on all architectures provide that facility.

Also, is there something that can tell the compiler if I have the members: float a, float b, float c, that I want them arranged in that order and not to mix them in memory?

I think you're guaranteed to get them in the order you write them, unless you have more than one kind of access specifier (e.g. public and private:), in which case the compiler can move things around.

I think you're asking for trouble. Given that the only thing you could do with a struct that was just a bundle of floats is read and write the floats, and that you can already do this with the array of floats, what advantage are you trying to get by treating the array of floats as a struct?

Moschops is mostly correct.

There are standard guarantees about the memory layout of the data members of a class, but it has to meet a number of requirements / restrictions. In standard terminology, this kind of class is called a standard-layout class, and it has the following requirements:

  1. It has no virtual functions
  2. It has no virtual base classes
  3. All its non-static data members have the same access control (public, private, protected)
  4. All its non-static data members, including any in its base classes, are in the same one class in the hierarchy
  5. The above rules also apply to all the base classes and to all non-static data members in the class hierarchy
  6. It has no base classes of the same type as the first defined non-static data member

If your class qualifies to the above requirements, then it can be considered a standard-layout class and it means that the data members will appear in memory in the same order as they appear in the class definition (and even when it's not standard layout, that is usually the case too, at least on all compilers AFAIK), and there will be nothing else in the class except for those data members. In other words, the class will appear, in memory, to be exactly the same as a C struct (and that's the whole purpose of this thing, to make those C++ classes binary-compatible with C structs).

That said, there can be padding, as Moschops points out. This is also true in C. The compiler is not required to put each data member contiguously next to each other in memory. Most computers these days have a 32bit or 64bit data bus, meaning that all memory transactions at the system bus level are done in packs of 32 or 64 bits. Therefore, it is preferrable to align the data members such that they fall on 32 or 64 bit intervals in memory, to minimize the required chunks of memory going through the data buses (and also avoid "false sharing"). So, when your data members don't align correctly, the compiler will add some padding to space them out into the correct alignment.

There is no standard way to tell the compiler that you don't want any padding to be applied between the data members of a class. However, most compilers have extensions (features specific to them) that allow you to do that, such as __attribute__((packed)) on GCC and #pragma pack on MSVC, which you can use as follow:

GCC:

struct __attribute__((packed)) Foo {
    char   a;
    int    b;
    double c;
};

MSVC:

#pragma pack(push, 1) // store previous pack value
                      // and set new value to 1 (no alignment)
struct Foo {
    char   a;
    int    b;
    double c;
};
#pragma pack(pop)     // restore previous pack value

The new standard C++11 has a alignas() feature that may seem similar to the above, however, alignas is not permitted to make the alignment less strict than it already is. Doing a "packing" like above is equivalent to setting the alignment requirement to 1, which is the lowest possible requirement (the bigger it is, the stricter it is), and alignas is only allowed to specify stricter requirements. So, if the alignment of float is 8, you cannot make it less than that with alignas, so, it cannot be used for this purpose. In other words, you cannot reduce padding with alignas, only increase it (which is useful for SSE and preventing false-sharing).

In my case I only have two constructors

The number of constructors or other member functions is irrelevant. You cannot have any virtual functions, but all the other functions are allowed (they don't affect the memory layout of a class).

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.