Strange thing about sizeof [duplicate] - c++

This question already has answers here:
How is the size of a C++ class determined?
(4 answers)
Closed 7 years ago.
Can anyone explain, why size of the objC is 8, not 12?
I think, that if it in the class C I have object with type int and in A, B - char, then after creation of the objC it should be 4 bytes for objA, objB and ObjC.
class A {
char a;
};
class B : A {
char b;
};
class C : B {
int c;
};
int main()
{
A objA;
B objB;
C objC;
cout << sizeof(objA) << endl; // 1
cout << sizeof(objB) << endl; // 2
cout << sizeof(objC) << endl; // 8! Why not 12?
return 0;
}
Edit 1:
In this case sizeof(objC) will be 12:
class A {
char a;
};
class B : A {
int b; // Here is int
};
class C : B {
char c; // Here is char
};

I believe that class C will have:
2x 1-byte chars
2-bytes of padding, so the int starts on a 4-byte boundary.
1x 4-byte integer
Making a total of 8-bytes
To keep the integer aligned on a boundary, there'll be 2-bytes of padding, making 8 bytes.
How do you get 12??
In your second example, class C will have:
a 1-byte char.
3-bytes of padding before the int. (keep the int on a 4-byte boundary)
a 4-byte int.
a 1-byte char.
Making a total of 9-bytes.
Sizes are rounded up to the nearest 4-bytes, which is 12.

In the first case, there is one padding. In the second case there are two paddings.
The first case will be:
+---+---+---+---+---+---+---+---+
| a | b | | | c |
+---+---+---+---+---+---+---+---+
<- 4 ->|<- 4 ->|
The second case will be:
+---+---+---+---+---+---+---+---+---+---+---+---+
| a | | | | b | c | | | |
+---+---+---+---+---+---+---+---+---+---+---+---+
<- 4 ->|<- 4 ->|<- 4 ->|

Related

what is wrong when i'm trying to access this array (2d ) in c++

below is the code that I'm trying to run
#include <iostream>
using namespace std;
int foo(int **a){
cout<<*(a+3)<<endl;
return 1;
}
int main(){
int a[2][2] = {{1,2},{3,4}};
std::cout << sizeof(a);
foo((int **)a);
}
when I have four elements in this array, shouldn't the value *(a+3) return a value 4, instead of that its returning an address and when i try to dereference that address (i.e. **(a+3)) i get segfault 11
Actually you are defining an array of arrays of integers. It can decay to a pointer to an array of integers, but it will not decay into a pointe to a pointer of integers.
It will help if you draw the memory layout:
+---------+---------+---------+---------+
| a[0][0] | a[0][1] | a[1][0] | a[1][1] |
+---------+---------+---------+---------+
| 1 | 2 | 3 | 4 |
+---------+---------+---------+---------+
If you let it decay into a pointer-to-array-of-integer:
int (*pa)[2] = a;
+---------+---------+---------+---------+
| pa[0] | pa[1] |
+---------+---------+---------+---------+
| 1 | 2 | 3 | 4 |
+---------+---------+---------+---------+
Note how sizeof(*pa) = 2 * sizeof(int). Each of these values can decay into a pointer to integer, but never into a pointer to a pointer:
int *p = pa[0];
Anyway, you can cast the decayed pointer-to-array-of-integer into a pointer to integers and access the four values directly:
int *p = (int*)a;
std::cout << p[3] << std::endl;
std::cout << *(p + 3) << std::endl;
The memory will be like this:
+---------+---------+---------+---------+
| p[0] | p[1] | p[2] | p[3] |
+---------+---------+---------+---------+
| 1 | 2 | 3 | 4 |
+---------+---------+---------+---------+
But if you cast it into a int** you will get meaningless values, because in memory there are no pointers, just integers.
A array is not a pointer. Yes it can decay to a pointer that does not mean it is one. If you want to pass a 2d array then you can use
int foo(int a[][2]);
or if you want to take any size array then you can use
template<std::size_t N>
int foo(int a[][N]);
You are dereferencing too far. a already points to the first element in the array. So **a treats the first value in the array as an address instead of a value. Try
foo((int *)a)
When you dereference int** you get int*. However, you are dereferencing a location with a value 4 that is interpreted as int*. That's why cout prints 0x4, because it formats it as an address. Try taking int* as parameter:
#include <iostream>
using namespace std;
int foo(int *a){
cout<<*(a+3)<<endl;
return 1;
}
int main(){
int a[2][2] = {{1,2},{3,4}};
std::cout << sizeof(a);
foo((int *)a);
}
It prints 4 then.
This is just an example of how to fix up this piece of code in particular, and is not the right way of doing things. Also as #rodrigo stated in the comments of his answer, if the size of an int is not equal to the size of its pointer, this is not going to work. I just wanted to show you why you thought it was printing an address - because it is being interpreted as one.

How to write and read bytes from unsigned variable

Here is what I'm trying to do:
I have two integers
int a = 0; // can be 0 or 1
int b = 3; // can be 0, 1, 2 or 3
Also I want to have
unsigned short c
to store that variables inside it.
For example, if I would store a inside c it will be looking like this:
00000000
^ here is a
Then I need to store b inside c. And it should look like following:
011000000
^^ here is b.
Also I would like to read that numbers back after writing them.
How can I do this?
Thanks for your suggestions.
Assuming those are binary representations of the numbers and assuming that you really meant to have five zeros to the right of b
01100000
^^ here is b
(the way you have it a and b overlap)
Then this is how to do it
// write a to c
c &= ~(1 << 7);
c |= a << 7;
// write b to c
c &= ~(3 << 5);
c |= b << 5;
// read a from c
a = (c >> 7)&1;
// read b from c
b = (c >> 5)&3;
You can accomplish this with C++ Bit Fields:
struct MyBitfield
{
unsigned short a : 1;
unsigned short b : 2;
};
MyBitfield c;
c.a = // 0 or 1
c.b = // 0 or 1 or 2 or 3

Wrong output of reference to pointer to int

I am trying to use a reference to pointer to int like in below program. But I am not getting the expected output.
Output:
9 5
5 9
Expecting:
9 5
9 5
Code:
#include <iostream>
using namespace std;
void swap (int *& a, int *&b)
{
int *t = a;
a = b;
b = t;
}
int main()
{
int a = 5, b = 9;
int *p = &a;
int *q = &b;
swap (p, q);
cout << *p << " " << *q << endl;
cout << a << " " << b << endl;
return 0;
}
Why is my expectation wrong? I head that reference is nothing just an other name of the target variable.
You swap the pointers, not the values. Your expectation is wrong.
You're swapping the values of the pointers.
Look at this illustration:
First, p is pointing at a, q is pointing at b:
p a
+---+ +---+
+ ------> | 5 |
+---+ +---+
q b
+---+ +---+
+ ------> | 9 |
+---+ +---+
After you swap p and q, q is pointing at a, and p is pointing at b:
q a
+---+ +---+
+ ------> | 5 |
+---+ +---+
p b
+---+ +---+
+ ------> | 9 |
+---+ +---+
But both a and b still have their old values.
In your case, you're swapping the pointers (and not the values). Since you're swapping the pointers, the actual values inside a and b remain unchanged. Hencewhy when you print the value of a, you get 5 and when you print b you get 9.
In general, you are swapping two pointers and not what they point to.
Maybe your function is confusing you as you are calling the values a and b. Your function swaps two pointers such that the first one now points where the second one was pointing, and the second points to where the first was pointing.
p was previously pointing to a and q to b. Now p points to b and q points to a thus your output is 9 5 5 9
There are references in your swap function. These are references to the pointers, so a and b in the function scope become aliases to the parameters passed in, i.e. p and q and thus modify p and q (to point elsewhere).
I head that reference is nothing just a other name of the target
variable
Yes, and target variable in your case is a pointer of the variable, not the variable. Because you're using * in the function declaration. Then, you're swaping pointers not values.
Use one of these ways:
void swap(int &a, int &b)
{
int t=a;
a=b;
b=t;
}
// ...
int a=5,b=9;
swap(a,b);
or
void swap(int *a, int *b)
{
int t=*a;
*a=*b;
*b=t;
}
// ...
int a=5,b=9;
swap(&a,&b);

C++: sizeof of struct with bit fields

Why is gcc giving returning 13 as the sizeof of the following class ?
It seems to me that we should get e (4 bytes) + d (4 bytes) + 1 byte (for a and b) = 9 bytes. If it was alignment, aren't most 32 bit systems aligned on 8 byte boundaries ?
class A {
unsigned char a:1;
unsigned char b:4;
unsigned int d;
A* e;
} __attribute__((__packed__));
int main( int argc, char *argv[] )
{
cout << sizeof(A) << endl;
}
./a.out
13
You are very likely running on a 64 bit platform and the size of the pointer is not 4 but 8 bytes. Just do a sizeof on A * and print it out.
The actual size of structs with bitfields is implementation dependent, so whatever size gcc decides it to be would be right.

Size of classes with virtual functions GCC/Xcode

Can anyone explain to me what is going on here? First off, I think most programmers know that a class with a virtual function has a vtbl and thus has 4 extra bytes on the top of it. As far as I know, that's fairly standard. I've tested this and taken advantage of this fact before to do load in place from a binary file with patched vtbls. For the last 6 months, I've been working in Xcode and just recently came across the need to do some load in place stuff, so I was looking into patching vtbls again. Just to make sure my understanding was correct, I wrote a sample program. Here it is:
class A
{
public:
virtual int getData()
{
return a;
}
virtual void print()
{
printf("hello\n");
}
int a;
};
class B : public A
{
public:
int getData()
{
return b;
}
int b;
};
class C : public B
{
public:
int getData()
{
return c;
}
void print()
{
printf("world\n");
}
int c;
};
class D
{
public:
int a;
int b;
};
int main (int argc, const char * argv[])
{
A* tA = new A();
tA->a = 1;
printf("A: %d\n", sizeof(A));
printf("A data: %d\n", tA->getData());
B* tB = new B();
tB->a = 2;
tB->b = 4;
printf("B: %d\n", sizeof(B));
printf("B data: %d\n", tB->getData());
C* tC = new C();
tC->c = 8;
printf("C: %d\n", sizeof(C));
printf("C data: %d\n", tC->getData());
A* aC = tC;
aC->print();
printf("D: %d\n", sizeof(D));
return 0;
}
My expected output was:
A: 8
A data: 1
B: 12
B data: 4
C: 16
C data: 8
world
D: 8
However, the output I'm getting is:
A: 16
A data: 1
B: 16
B data: 4
C: 24
C data: 8
world
D: 8
Anybody have any idea what's going on here? Thanks!
Instances of classes A through C contain a vptr, a pointer to the virtual function table for the dynamic type. This pointer occupies 8 bytes on your 64-bit machine (or 4 bytes on a 32-bit machine). Each int member takes up 4 bytes.
The minimum value of sizeof(Class) is the sum of sizeof(member) for all members. If it were like that, then
sizeof(A) = 8 (vptr) + 4 (int a) = 12
sizeof(B) = 8 (vptr) + 4 (int a) + 4 (int b) = 16
sizeof(C) = 8 (vptr) + 4 (int a) + 4 (int b) + 4 (int c) = 20
sizeof(D) = 4 (int a) + 4 (int b) = 8
However, this is only the minimum size. Compilers usually increase this size to a multiple of sizeof(void*), which is 8 bytes here. This process is called aligning. It may look like this wastes memory, but this is outweighed by a performance gain: The CPU can read aligned data much faster than non-aligned data.
By the way, your expected result would have been correct if you were on a 32-bit machine. Pointers (esp. vptr) are 4 bytes wide there, and alignment is also to multiples of 4 bytes. Since all data members of the classes in question are 4 bytes big then, alignment wouldn't do anything there.