views:

346

answers:

8

If I have a list of global variables like this...

int a;
char b;
float c[10];
double d[3];

and I have an identical sequence of variables listed inside a class...

class test_type
{
    int a;
    char b;
    float c[10];
    double d[3];
}

is it guaranteed that the arrangement of all the variables in memory are identical. i.e. is 'b' guaranteed to be stored immediately after 'a' in both the globals list and the class list?

EDIT: I ask because I wanted to A) copy the data from one to the other as a "job lot" and B) I wanted to check for any differences between them as a job lot. If the answer to the main question is "no" then does anyone have any suggestions as to how I get round the problem, preferably leaving existing code as unaltered as possible.

+8  A: 

No. I don't think the C++ standard guarantees anything about the memory layout of global variables.

JesperE
It actually does guarantee something. The order of consecutivly declared class/struct elements with the same access specifier is retained. There might be some padding involved, though.
sellibitze
Yes, but Jesper said "global variables".
Skilldrick
True. I missed that, sorry.
sellibitze
A: 

Memory allocation is compiler dependent. So, contiguous allocation, or identical allocation of global and class member variables, cannot be guaranteed.

Igor Oks
A: 

No, you can't rely on that. It's up to compiler how to allocate memory for the variables.

grigy
A: 

No, it is not guaranteed. Depending on what you would like to do, you can use pointer-to-member operators to make sure you know the relative address of a member variable.

So in your class:

class test_type
{
    int a;
    char b;
    float c[10];
    double d[3];
}

void* pa = &test_type::a;
void* pb = &test_type::b;
void* pc = &test_type::c;
void* pd = &test_type::d;

void main()
{
  std::cout << "Relative address of member 'a' " << (int)pa <<  std::endl;
  std::cout << "Relative address of member 'b' " << (int)pb <<  std::endl;
  std::cout << "Relative address of member 'c' " << (int)pc <<  std::endl;
  std::cout << "Relative address of member 'd' " << (int)pd <<  std::endl;
}

As far as I know it is working with msvc and gcc as well.

progician
That's because the order of variables defined within a class/struct most certainly is guaranteed. It's only global variables that aren't.
kdgregory
Maybe you're right but my solution doesn't mean any extra operations and generally saying it's not relying on a principle what can be easily changed by implementation. (I'm not totally sure how does affect this the alignment issues...)
progician
Your "solution" demonstrates something that's known to be true. It doesn't solve the OP's desired goal of copying global variables into a structure with a single operation.
kdgregory
kdgregory
Okay, I missed the point of the question. :$
progician
+1  A: 

C/C++ standards does not require variables to be stored in the order of their declarations. So compilers are free to store variables in the order they want. But it is guaranteed that they will be initialized in the order of their declaration. This is true for both global and class member variables.

Some notes on global variables: In a compilation unit they will be initialized in the specified order, but this gurantee is not applied across compilation units.

Vijay Mathew
A: 

Mick - in order to do what you want (copy/test), you will simply need to

  • add a constructor to test_type class as well as a non-constructor init_from_globals() (whose code copies the 4 values one by one, the arrays copied in a loop or via memcopy).

  • Add a "diff_from_globals()" method, which again diffs the 4 members individually

It's a bit less efficient/elegant than what you wanted as far as implementation, but wrapped in a method, the in-elegance is fully hidden from the rest of the code :)

DVK
+5  A: 

Why don't you simply use a global object of type test_type instead of defining multiple global variables?

class test_type
{
    int a;
    char b;
    float c[10];
    double d[3];
};

test_type global;

Now, it's a piece of cake to initialize a new test_type object with a copy of "global".

sellibitze
A: 

I think people are missing the point. It is always dangerous to assume any layout as this can change from CPU to CPU, compiler to compiler and even degree of optimisation.

C++ will generate a default copy assignment function as if you had written this:

class test_type
{
    int a;
    char b;
    float c[10];
    double d[3];
public:
    test_type &operator=(const test_type &other)
    {
     // copy all of the members one by one.
    }
}

The only caveat is that the default operator just copies members and that includes pointers. If you have dynamically allocated something that is attached to a pointer, you will have to deal with the new memory allocation and data copying explicitely in the operator.

Dr. Tim
So? In this case the implicitly generated assignment operator does no harm.
sellibitze
Of course not. I think it is good practice to create classes for which the default operator works correctly. I use std::string instead of char * for example.
Dr. Tim