The C++ Standard makes few guarantees about how types are represented in memory:
Base two is guaranteed for integral numbers.
Two's complement is guaranteed for negative integral numbers.
Plain Old Data (POD) types have C-compatible layout: Member variables are stored in their order of declaration.
int holds at least 16 bits.
In particular, the following may be common but are not guaranteed on all current architectures, and in particular are liable to be broken on newer architectures:
int is not exactly 32 bits, nor any particular fixed size.
Pointers and ints don't always have the same size and can't always be freely cast to one another.
Class layout does not always store bases and members in declaration order.
There can be gaps between the members of a class (even a POD) for alignment.
offsetof only works for PODs, not all classes (but compilers might not emit errors).
A class might have hidden fields.
Pointers might not look like integers at all. If two pointers are ordered, and you cast them to integral values, the resulting values might not be ordered the same way.
You can't portably assume anything about the placement in memory of automatic variables, or about the direction in which the stack grows.
Pointers to functions might have a different size than void*, even though some APIs force you to assume that their sizes are the same.
You can't always write just any object at just any memory address, even if you have enough space, due to alignment issues.
Just define types appropriately, then read and write data using those types instead of thinking bits and words and addresses. The C++ memory model ensures efficient execution without forcing you to rely on manipulating representation. So don't.