#include <iostream>
using namespace std;
class V3 {
public:
double x, y, z;
V3(double a, double b, double c) {
x=a;
y=b;
z=c;
cout << "Addresses are " << &x << " " << &y << " " << &z << endl;
}
};
int main() {
V3 a(1,1,1), b(2,2,2), c(3,3,3), d(4,4,4);
cout << sizeof(a) << " " << sizeof(b) << " " << sizeof(c) << " " << sizeof(d) << endl;
}
In the code mentioned above, I'm trying to see how C++ stores objects in memory. On running this code, I get the following output -
Addresses are 0x7ffc5996b160 0x7ffc5996b168 0x7ffc5996b170
Addresses are 0x7ffc5996b180 0x7ffc5996b188 0x7ffc5996b190
Addresses are 0x7ffc5996b1a0 0x7ffc5996b1a8 0x7ffc5996b1b0
Addresses are 0x7ffc5996b1c0 0x7ffc5996b1c8 0x7ffc5996b1d0
24 24 24 24
So for object b, I wonder why I did not get 0x7ffc5996b178 as my address. Why is C++ skipping 8 bytes before starting the next object?
Converting a variety of comments into a Community Wiki answer.
Are the assignments necessary? Does anything change if you use V3(double a, double b, double c) : x(a), y(b), z(c) { cout << …; }? (I don't expect there to be a difference.) Did you try printing the addresses of the class objects in main()? Does that throw any light on things? Ultimately, though, your question is futile — the compiler is allowed to use any layout and alignment it chooses as long as it gives the correct results.
Just a guess: x86 cache lines are 64 bytes. By aligning this way, the first 2 objects would fit in 1 cache line, and the third would fit in a second cache line. If they were not aligned this way, the third object would be split across 2 cache lines which is bad. As already said though, it's not necessarily well-defined.
If compiled using clang on arch the objects are densely packed in memory, when using g++ they are not.
Related
I am learning about double and float and what the difference is. I ran a piece of code as posted below, to see how much memory is allocated depending on how many integers I add and decimal points but it seems that no matter how many integers I type I always get size 8 bytes for both float and double. I learned that float occupies 4 bytes, but Im starting to think that on modern computers that's not the case and perhaps this was the case back in the days and today we can use them interchangeably without affecting the results? Am I missing something here?
// C++ program to sizes of data types
#include<iostream>
using namespace std;
int main()
{
cout << "Size of int : " << sizeof(11111111111111111) << " bytes" << endl;
cout << "Size of float : " << sizeof(11111111111111111111111111111111111111111111111111111111111.1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111) << " bytes" <<endl;
cout << "Size of double : " << sizeof(.11111111111111111111111111111111111111111111111111111) << " bytes" << endl;
return 0;
}
You print the size of double on both lines, because both floating point literals has the type of double. If you want to create a float literal, append an f to it: 1.0f. This has the type of float. If you don't append an f to it, it will have the type of double.
Or you can just simply use sizeof(float).
I've been reading up on placement new, and I'm not sure if I'm "getting" it fully or not when it comes to proper alignment.
I've written the following test program to attempt to allocate some memory to an aligned spot:
#include <iostream>
#include <cstdint>
using namespace std;
unsigned char* mem = nullptr;
struct A
{
double d;
char c[5];
};
struct B
{
float f;
int a;
char c[2];
double d;
};
void InitMemory()
{
mem = new unsigned char[1024];
}
int main() {
// your code goes here
InitMemory();
//512 byte blocks to write structs A and B to, purposefully misaligned
unsigned char* memoryBlockForStructA = mem + 1;
unsigned char* memoryBlockForStructB = mem + 512;
unsigned char* firstAInMemory = (unsigned char*)(uintptr_t(memoryBlockForStructA) + uintptr_t(alignof(A) - 1) & ~uintptr_t(alignof(A) - 1));
A* firstA = new(firstAInMemory) A();
A* secondA = new(firstA + 1) A();
A* thirdA = new(firstA + 2) A();
cout << "Alignment of A Block: " << endl;
cout << "Memory Start: " << (void*)&(*memoryBlockForStructA) << endl;
cout << "Starting Address of firstA: " << (void*)&(*firstA) << endl;
cout << "Starting Address of secondA: " << (void*)&(*secondA) << endl;
cout << "Starting Address of thirdA: " << (void*)&(*thirdA) << endl;
cout << "Sizeof(A): " << sizeof(A) << endl << "Alignof(A): " << alignof(A) << endl;
return 0;
}
Output:
Alignment of A Block:
Memory Start: 0x563fe1239c21
Starting Address of firstA: 0x563fe1239c28
Starting Address of secondA: 0x563fe1239c38
Starting Address of thirdA: 0x563fe1239c48
Sizeof(A): 16
Alignof(A): 8
The output appears to be valid, but I still have some questions about it.
Some questions I have are:
Will fourthA, fifthA, etc... all be aligned as well?
Is there a simpler way of finding a properly aligned memory location?
In the case of struct B, it is set up to not be memory friendly. Do I need to reconstruct it so that the largest members are at the top of the struct, and the smallest members are at the bottom? Or will the compiler automatically pad everything so that it's member d will not be malaligned?
Will fourthA, fifthA, etc... all be aligned as well?
yes if the alignement of a type is a multiple of the size
witch is (i think) always the case
Is there a simpler way of finding a properly aligned memory location?
yes
http://en.cppreference.com/w/cpp/language/alignas
or
http://en.cppreference.com/w/cpp/memory/align
as Dan M said.
In the case of struct B, it is set up to not be memory friendly. Do I need to reconstruct it so that the largest members are at the top of the struct, and the smallest members are at the bottom? Or will the compiler automatically pad everything so that it's member d will not be malaligned?
you should reorganize if you think about it.
i don't think compiler will reorganize element in a struct for you.
because often when interpreting raw data (coming from file, network ...) this data is often just interpreted as a struct and 2 compiler reorganizing differently could break code.
I hope my explanation are clear and that I did not make any mistakes
I'm trying to learn about stack and heap at c++ and just started to print tests to learn how it's work.
I wrote this code:
`#include <iostream>
using namespace std;
int main (){
int a;
int b;
int *c;
int *c2;
int *d{new int};
cout << &a << " a= " << a << endl;
cout << &b << " b= " << b << endl;
cout << &c << " c= " << c << endl;
cout << &c2 << " c2= " << c2 << endl;
cout << &d << " d= " << d << endl;
delete d;
return 0;
}
the output is:
0x7ffefad88d00 a= 124
0x7ffefad88d04 b= 0
0x7ffefad88d08 c= 0
0x7ffefad88d10 c2= 0x400b20
0x7ffefad88d18 d= 0xec9c20
There are 3 things I do not understand:
why a value is 124?
why c value is 0 and not a pointer like c2 that have the same syntax?
why c size is just 2 byts and not 4?
a, b, c, d and the value of *d are uninitialized, reading them is undefined behavior. Anything can happen, nobody can predict the value of those variables. See this question for more information.
About the printout of the pointers, many implementations trim leading 0s. See this question. If I try to print out the values of pointers in Visual Studio 2015, I get the leading zeros.
why a value is 124?
a is uninitialized, hence reading it will give you unpredictable value. Reading uninitialized non-static local variable is UB. But, uninitialized global and static variables are initialized with 0 at compile time and reading them is fine.
why c value is 0 and not a pointer like c2 that have the same syntax?
c is also uninitialized, so what it points to is also undefined as mentioned above. It is a pointer like c2, but it points to NULL (which is 0).
why c size is just 2 bytes and not 4?
c size of a pointer is architecture and/or compiler dependent. In this case c occupied 8 bytes. subtract the address of c from the address of c2.
0x7ffefad88d10 - 0x7ffefad88d08 = 0x000000000008 these are hexadecimal values not decimal.
So, c is actually a pointer like c2 and occupies same space in the memory.
Following the topic How is an array aligned in C++ compared to a type contained? I made an experiment.
Here is the code:
#include<iostream>
using namespace std;
int main()
{
const int N = 12;
{
float p1[N], p2[N];
cout << p1 << " " << p2 << " " << p2 - p1 << endl;
}
{
float* p1, *p2;
// allocate memory
p1 = new float[N];
p2 = new float[N];
cout << p1 << " " << p2 << " " << p2 - p1 << endl;
delete[] p1;
delete[] p2;
}
}
According to the cited question and wiki I would expect that p1 and p2 would be sizeof(float) == 4 bytes aligned. But the result is:
0x7fff4fd2b410 0x7fff4fd2b440 12
0x7f8cc9c03bd0 0x7f8cc9c03c00 12
Same 12 distance between arrays for N = 9, 11 and 12. Distance (p2-p1) is 8 for N = 8.
So it looks like float arrays is 16 bytes aligned. Why?
P.S.
My processor is Intel Core i7
Compiler - g++ 4.6.3
It appears that putting arrays in a structure one can get 10 floats distance:
const int N = 10;
struct PP{
float p1[N], p2[N];
};
int main() {
PP pp;
cout << pp.p1 << " " << pp.p2 << " " << pp.p2 - pp.p1 << endl;
}
0x7fff50139440 0x7fff50139468 10
Memory allocated by operator new always has suitable alignment for any object type, whatever the actual type being created. Additionally, it may also have a wider alignment (for example, alignment with a cache line) to improve performance.
If you replace your dynamic arrays with automatic ones (or better still, make them consecutive members of a class), then you may see narrower alignments. Or you may not; the exact details of how objects are aligned are up to the compiler, as long as it meets the minimum requirement for the type.
The application I am working on receives C style structs from an embed system whose code was generated to target a 16 bit processor. The application which speaks with the embedded system is built with either a 32 bit gcc compiler, or a 32 bit MSVC c++ compiler. The communication between the application and the embedded system takes place via UDP packets over ethernet or modem.
The payload within the UDP packets consist of various different C style structs. On the application side a C++ style reinterpret_cast is capable of taking the unsigned byte array and casting it into the appropriate struct.
However, I run into problems with reinterpret_cast when the struct contains enumerated values. The 16 bit Watcom compiler will treat enumerated values as an uint8_t type. However, on the application side the enumerated values are treated as 32 bit values. When I receive a packet with enumerated values in it the data gets garbled because the size of the struct on the application side is larger the struct on the embedded side.
The solution to this problem, so far, has been to change the enumerated type within the struct on the application side to an uint8_t. However, this is not an optimal solution because we can no longer use the member as an enumerated type.
What I am looking for is a solution which will allow me to use a simple cast operation without having to tamper with the struct definition in the source on the application side. By doing so, I can use the struct as is in the upper layers of my application.
As noted, correctly deal with the issue is proper serialization and deserialization.
But it doesn't mean we can't try some hacks.
Option 1:
If you particular compiler support packing the enum (in my case gcc 4.7 in windows), this might work:
typedef enum { VALUE_1 = 1, VALUE_2, VALUE_3 }__attribute__ ((__packed__)) TheRealEnum;
Option 2:
If your particular compiler supports class sizes of < 4 bytes, you can use a HackedEnum class which uses operator overloading for the conversion (note the gcc attribute you might not want it):
class HackedEnum
{
private:
uint8_t evalue;
public:
void operator=(const TheRealEnum v) { evalue = v; };
operator TheRealEnum() { return (TheRealEnum)evalue; };
}__attribute__((packed));
You would replace TheRealEnum in your structures for HackedEnum, but you still continue using it as TheRealEnum.
A full example to see it working:
#include <iostream>
#include <stddef.h>
using namespace std;
#pragma pack(push, 1)
typedef enum { VALUE_1 = 1, VALUE_2, VALUE_3 } TheRealEnum;
typedef struct
{
uint16_t v1;
uint8_t enumValue;
uint16_t v2;
}__attribute__((packed)) ShortStruct;
typedef struct
{
uint16_t v1;
TheRealEnum enumValue;
uint16_t v2;
}__attribute__((packed)) LongStruct;
class HackedEnum
{
private:
uint8_t evalue;
public:
void operator=(const TheRealEnum v) { evalue = v; };
operator TheRealEnum() { return (TheRealEnum)evalue; };
}__attribute__((packed));
typedef struct
{
uint16_t v1;
HackedEnum enumValue;
uint16_t v2;
}__attribute__((packed)) HackedStruct;
#pragma pop()
int main(int argc, char **argv)
{
cout << "Sizes: " << endl
<< "TheRealEnum: " << sizeof(TheRealEnum) << endl
<< "ShortStruct: " << sizeof(ShortStruct) << endl
<< "LongStruct: " << sizeof(LongStruct) << endl
<< "HackedStruct: " << sizeof(HackedStruct) << endl;
ShortStruct ss;
cout << "address of ss: " << &ss << " size " << sizeof(ss) <<endl
<< "address of ss.v1: " << (void*)&ss.v1 << endl
<< "address of ss.ev: " << (void*)&ss.enumValue << endl
<< "address of ss.v2: " << (void*)&ss.v2 << endl;
LongStruct ls;
cout << "address of ls: " << &ls << " size " << sizeof(ls) <<endl
<< "address of ls.v1: " << (void*)&ls.v1 << endl
<< "address of ls.ev: " << (void*)&ls.enumValue << endl
<< "address of ls.v2: " << (void*)&ls.v2 << endl;
HackedStruct hs;
cout << "address of hs: " << &hs << " size " << sizeof(hs) <<endl
<< "address of hs.v1: " << (void*)&hs.v1 << endl
<< "address of hs.ev: " << (void*)&hs.enumValue << endl
<< "address of hs.v2: " << (void*)&hs.v2 << endl;
uint8_t buffer[512] = {0};
ShortStruct * short_ptr = (ShortStruct*)buffer;
LongStruct * long_ptr = (LongStruct*)buffer;
HackedStruct * hacked_ptr = (HackedStruct*)buffer;
short_ptr->v1 = 1;
short_ptr->enumValue = VALUE_2;
short_ptr->v2 = 3;
cout << "Values of short: " << endl
<< "v1 = " << short_ptr->v1 << endl
<< "ev = " << (int)short_ptr->enumValue << endl
<< "v2 = " << short_ptr->v2 << endl;
cout << "Values of long: " << endl
<< "v1 = " << long_ptr->v1 << endl
<< "ev = " << long_ptr->enumValue << endl
<< "v2 = " << long_ptr->v2 << endl;
cout << "Values of hacked: " << endl
<< "v1 = " << hacked_ptr->v1 << endl
<< "ev = " << hacked_ptr->enumValue << endl
<< "v2 = " << hacked_ptr->v2 << endl;
HackedStruct hs1, hs2;
// hs1.enumValue = 1; // error, the value is not the wanted enum
hs1.enumValue = VALUE_1;
int a = hs1.enumValue;
TheRealEnum b = hs1.enumValue;
hs2.enumValue = hs1.enumValue;
return 0;
}
The output on my particular system is:
Sizes:
TheRealEnum: 4
ShortStruct: 5
LongStruct: 8
HackedStruct: 5
address of ss: 0x22ff17 size 5
address of ss.v1: 0x22ff17
address of ss.ev: 0x22ff19
address of ss.v2: 0x22ff1a
address of ls: 0x22ff0f size 8
address of ls.v1: 0x22ff0f
address of ls.ev: 0x22ff11
address of ls.v2: 0x22ff15
address of hs: 0x22ff0a size 5
address of hs.v1: 0x22ff0a
address of hs.ev: 0x22ff0c
address of hs.v2: 0x22ff0d
Values of short:
v1 = 1
ev = 2
v2 = 3
Values of long:
v1 = 1
ev = 770
v2 = 0
Values of hacked:
v1 = 1
ev = 2
v2 = 3
On the application side a C++ style reinterpret_cast is capable of taking the unsigned byte array and casting it into the appropriate struct.
The layout of structs is not required to be the same between different implementations. Using reinterpret_cast in this way is not appropriate.
The 16 bit Watcom compiler will treat enumerated values as an uint8_t type. However, on the application side the enumerated values are treated as 32 bit values.
The underlying type of an enum is chosen by the implementation, and is chosen in an implementation defined manner.
This is just one of the many potential differences between implementations that can cause problems with your reinterpret_cast. There are also actual alignment issues if you're not careful, where the data in the received buffer isn't appropriately aligned for the types (e.g., an integer that requires four byte alignment ends up one byte off) which can cause crashes or poor performance. Padding might be different between platforms, fundamental types might have different sizes, endianess can differ, etc.
What I am looking for is a solution which will allow me to use a simple cast operation without having to tamper with the struct definition in the source on the application side. By doing so, I can use the struct as is in the upper layers of my application.
C++11 introduces a new enum syntax that allows you to specify the underlying type. Or you can replace your enums with integral types along with a bunch of predefined constants with manually declared values. This only fixes the problem you're asking about and not any of the other ones you have.
What you should really do is proper serialization and deserialization.
Put your enumerated type inside of a union with a 32-bit number:
union
{
Enumerated val;
uint32_t valAsUint32;
};
This would make the embedded side have it expanded to 32-bit. Should work as long as both platforms are little-endian and the structs are zero-filled initially. This would change wire format, though.
If by "simple cast operation" you mean something that's expressed in the source code, rather than something that's necessarily zero-copy, then you can write two versions of the struct -- one with enums, one with uint8_ts, and a constructor for one from the other that copies it element-by-element to repack it. Then you can use an ordinary type-cast in the rest of the code. Since the data sizes are fundamentally different (unless you use the C++11 features mentioned in another answer), you can't do this without copying things to repack them.
However, if you don't mind some small changes to the struct definition on the application side, there are a couple of options that don't involve dealing with bare uint8_t values. You could use aaronps's answer of a class that is the size of a uint8_t (assuming that's possible with your compiler) and implicitly converts to and from an enum. Alternately, you could store the values as uint8_ts and write some accessor methods for your enum values that take the uint8_t data in the struct and convert it to an enum before returning it.