How to do it
Yes you can do it. A simple way to do this is what you are doing now, this is the distribution of different bits of an integer to different values. For you, this looks like a 32-bit int:
|3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 | | | |1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 | 7 |6 5 4 3 2 1 0| | Age |Gender| Height |
When you change bit eight to the right, you take only the age parts of the number. If you moved seven to the right and masked it 1, i.e. value >>> 7 & 1 , you will get an answer. And if you just mask the bottom seven bits (i.e. value & 0x7F ), then you get the height.
Why is it fragile
Your example is missing something important: a range of values. For example, the height value can never exceed 127. If you try to save a height of 128 or higher, the way you write it now will cause part of the height to overwrite the floor, because you need eight bits to store a large value. This is why random numbers do not work.
In the same way, if someone accidentally puts a gender that is not zero or one, then he will ruin part of the age value, because you simply cannot keep a number that is high in one bit.
A way to fix this in the assignment is to insert bit masks, for example:
packed_info = (((age << 1) | (gender & 1)) << 7) | (height & 0x7f);
When you do this, you can be sure that gender will not overwrite age and height will not overwrite others. However, if you set it to a height greater than 127, mod 127 will be used.
Why you should not usually
Because it is prone to errors and integers do not take up a lot of memory. You can't just remember its int anymore, you need to remember what the bit layout looks like. It’s easier to just save three int s.
However, this kind of thing is still being done when the transmission speed matters. (For example, digital television or other video, digital audio, Ethernet protocols, etc.)