2
struct Vector { float x, y, z; }; func(Vector *vectors) {...} usage: load float *coords = load(file); func(coords); 

I have a question about the alignment of structures in C++. I will pass a set of points to the function func(). Is is OK to do it in the way shown above, or is this relying on platform-dependent behavior? (it works at least with my current compiler) Can somebody recommend a good article on the topic?

Or, is it better to directly create a set of points while loading the data from the file?

Thanks

3
  • 2
    Your post is very difficult to read. Commented Jul 7, 2010 at 16:54
  • 3
    That is not C++ the way you have it right now. Your usage won't compile and doesn't demonstrate how you want to use the vector in question. Please modify the usage to show what load() is accepting and returning. Also, coords is a float pointer in your example (sort of) and func wants a vector pointer. Commented Jul 7, 2010 at 17:02
  • 1
    Writing binary data to a file and reading that back is non portable. There are just too many variations between machines. It is much easier to serialize the data (write it as text) then serialize on input back into the structure. Commented Jul 7, 2010 at 17:39

5 Answers 5

3

Structure alignment is implementation-dependent. However, most compilers give you a way of specifying that a structure should be "packed" (that is, arranged in memory with no padding bytes between fields). For example:

struct Vector { float x; float y; float z; } __attribute__((__packed__)); 

The above code will cause the gcc compiler to pack the structure in memory, making it easier to dump to a file and read back in later. The exact way to do this may be different for your compiler (details should be in your compiler's manual).

I always list members of packed structures on separate lines in order to be clear about the order in which they should appear. For most compilers this should be equivalent to float x, y, z; but I'm not certain if that is implementation-dependent behavior or not. To be safe, I would use one declaration per line.

If you are reading the data from a file, you need to validate the data before passing it to func. No amount of data alignment enforcement will make up for a lack of input validation.

Edit:

After further reading your code, I understand more what you are trying to do. You have a structure that contains three float values, and you are accessing it with a float* as if it were an array of floats. This is very bad practice. You don't know what kind of padding that your compiler might be using at the beginning or end of your structure. Even with a packed structure, it's not safe to treat the structure like an array. If an array is what you want, then use an array. The safest way is to read the data out of the file, store it into a new object of type struct Vector, and pass that to func. If func is defined to take a struct Vector* as an argument and your compiler is allowing you to pass a float* without griping, then this is indeed implementation-dependent behavior that you should not rely on.

Sign up to request clarification or add additional context in comments.

1 Comment

And aside from packing/structure alignment, don't forget about endianness issues!
2

Use an operator>> extraction overload.

std::istream& operator>>(std::istream& stream, Vector& vec) { stream >> vec.x; stream >> vec.y; stream >> vec.z; return stream; } 

Now you can do:

std::ifstream MyFile("My Filepath", std::ios::openmodes); Vector vec; MyFile >> vec; func(&vec); 

2 Comments

You forgot to return a value from you stream operator.
You should probably make your stream operator return a stream. This allows chaining of stream operations.
0

Prefer passing by reference than passing by pointer:

void func(Vector& vectors) { /*...*/ } 

The difference here between a pointer and a reference is that a pointer can be NULL or point to some strange place in memory. A reference refers to an existing object.

As far as alignment goes, don't concern yourself. Compilers handle this automagically (at least alignment in memory).

If you are talking about alignment of binary data in a file, search for the term "serialization".

Comments

0

First of all, your example code is bad:

load float *coords = load(file); func(coords); 

You're passing func() a pointer to a float var instead of a pointer to a Vector object.

Secondly, Vector's total size if equal to (sizeof(float) * 3), or in other words to 12 bytes.
I'd consult my compiler's manual to see how to control the struct's aligment, and just to get a peace of mind I'd set it to, say 16 bytes.
That way I'll know that the file, if contains one vector, is only 16 bytes in size always and I need to read only 16 bytes.

Edit:
Check MSVC9's align capabilities .

2 Comments

Don't assume that Vector is 12 bytes. The compiler is free to add padding at any point. The compiler will set the size and alignment to make accessing an array of these objects as efficient as possible. Trying to fight the compiler and set a specific size to a structure is counter productive (and non portable).
@Martin: You're 100% correct, yet my answer is as per this specific question and of course that "12" is just an example.
0

Writing binary data is non portable between machines.
About the only portable thing is text (even then can not be relied as not all systems use the same text format (luckily most accept the 127 ASCII characters and hopefully soon we will standardize on something like Unicode (he says with a smile)).

If you want to write data to a file you must decide the exact format of the file. Then write code that will read the data from that format and convert it into your specific hardware's representation for that type. Now this format could be binary or it could be a serialized text format it does not matter much in performance (as the disk IO speed will probably be your limiting factor). In terms of compactness the binary format will probably be more efficient. In terms of ease of writing decoding functions on each platform the text format is definitely easier as a lot of it is already built into the streams.

So simple solution:
Read/Write to a serialized text format.
Also no alignment issues.

#include <algorithm> #include <fstream> #include <vector> #include <iterator> struct Vector { float x, y, z; }; std::ostream& operator<<(std::ostream& stream, Vector const& data) { return stream << data.x << " " << data.y << " " << data.z << " "; } std::istream& operator>>(std::istream& stream, Vector& data) { return stream >> data.x >> data.y >> data.z; } int main() { // Copy an array to a file Vector data[] = {{1.0,2.0,3.0}, {2.0,3.0,4.0}, { 3.0,4.0,5.0}}; std::ofstream file("plop"); std::copy(data, data+3, std::ostream_iterator<Vector>(file)); // Read data from a file. std::vector<Vector> newData; // use a vector as we don't know how big the file is. std::ifstream input("inputFile"); std::copy(std::istream_iterator<Vector>(input), std::istream_iterator<Vector>(), std::back_inserter(newData) ); } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.