Reputation: 7455
Surprisingly little information turns up by the search engine. The book C++ Concurrency In Action, in chapter 5 states:
In C++, it's all about objects and memory locations.
Then later,
Whatever its type, an object is stored in one or more memory locations. Each such memory location is either an object (or subobject) of a scalar type such as
unsigned short
ormy_class*
or a sequence of adjacent bit fields.
The emphasis is as printed in the book, so clearly a fundamental concept, yet there is no definition.
So, what is it? Is it a universal concept or something more narrowly defined in the C++11 standard? How should I think about it in terms of 32- vs 64-bit architecture and the CPU registers? What does it mean that a bit field (or rather, a series of adjacent bit fields of non-zero length) are part of the same memory location? This last statement implies that a memory location can store data of arbitrary length.
If the above quote is the definition, then I am hoping to see a discussion helping to develop intuitive understanding of the concept.
Upvotes: 7
Views: 2894
Reputation: 20579
This answer provides the quotes from the standard for the language lawyers. This answer is meant to be an addition to the existing answers.
Per [intro.memory]/3:
A memory location is either an object of scalar type or a maximal sequence of adjacent bit-fields all having nonzero width. [ Note: Various features of the language, such as references and virtual functions, might involve additional memory locations that are not accessible to programs but are managed by the implementation. — end note ] Two or more threads of execution can access separate memory locations without interfering with each other.
[ Note: Thus a bit-field and an adjacent non-bit-field are in separate memory locations, and therefore can be concurrently updated by two threads of execution without interference. The same applies to two bit-fields, if one is declared inside a nested struct declaration and the other is not, or if the two are separated by a zero-length bit-field declaration, or if they are separated by a non-bit-field declaration. It is not safe to concurrently update two bit-fields in the same struct if all fields between them are also bit-fields of nonzero width. — end note ]
[ Example: A class declared as
struct { char a; int b:5, c:11, :0, d:8; struct {int ee:8;} e; }
contains four separate memory locations: The member
a
and bit-fieldsd
ande.ee
are each separate memory locations, and can be modified concurrently without interfering with each other. The bit-fieldsb
andc
together constitute the fourth memory location. The bit-fieldsb
andc
cannot be concurrently modified, butb
anda
, for example, can be. — end example ]
Where a scalar type is a possibly cv-qualified ([basic.types]/9)
arithmetic type (integral or floating-point),
enumeration type,
pointer type,
pointer-to-member type, or
std::nullptr_t
.
Upvotes: 2
Reputation: 75688
Memory is a "thing" capable of storing information over time. That is what human memory is, that is what computer memory is.
Wires (think of both cables and imprinted wires on a circuit board) are physical entities that transmit information (in a way or another). Circuit elements such as logic gates are physical entities that transform information. But they are not capable of storing the information. Memory is a hardware device which is capable of storing information and, of course give back that information over time.
In computers the most used logical memory organization is in bits and bites. A bit stores a binary digit which can have the value 0
or the value 1
.
Physically, in integrated circuits a bit is more-or-less a transistor. On hard-disks it is a magnetic zone on the platan, on CDs it's a reflective or not zone on the disk.
Bits are grouped by 8 in bytes. In order to "store information" and "retrieve information" from memory you need the memory to be addressable. I.e. you need a way to uniquely identify the memory location where you want to store the information or from where to load it. Computer memory is byte addressed, which means that every byte has a unique address. The physical addresses of the memory bytes are contiguous. It starts from address 0x0000
and goes on consecutively without any gaps in it.
C++ doesn't concern itself with the hardware underneath. But logically things are the same: bits organized in bytes, memory is byte-addressed.
A type in C++ is defined by the size of the memory it occupies, the set of possible values and the set of operations possible on the data.
Let's take std::uint8_t
. Its size is 1
which means it occupies just 1 byte. Since 1 byte has 8 bits (on most implementations) there are 2^8 possible different values for an std::uint8_t
type. Because it's easy, the value of an unsigned char
is the value of a number in base 2 formed by the bits of the byte. E.g. for the bits 0000 0110
the value is the value of the number 0000 0110 (base 2) == 6 (base 10)
For a larger data type, for instance std::int32_t
the size is 4
so it occupies 4 adjacent bytes. That means 2^32
possible values. The question is again how do you map the effective bit patterns you find in memory at those 4 bytes to an integer? That is called the encoding scheme. At a hardware level we care about little or big endian machines which dictates in which order we take the bytes. After that the sequence of bits is converted to the number (or in reverse, the number is converted to the sequence of bits) by the Two's complement (mandatory since C++20) encoding scheme.
Except that for archaic reasons the smallest addressable memory unit is not called a byte. It's called char
(badum tss).
Upvotes: 3
Reputation: 4435
According to cppreference.com, a memory location is:
int
), a pointer type (e.g. struct timeval*
), an enum type (e.g. std::regex_constants::error_type
), or the recently minted std::nullptr_t
type – OR:… q.v https://en.cppreference.com/w/cpp/language/memory_model#Memory_location
… Which that is all intuitively what you find at a “memory location” – what the contents of a variable variable
might be when &variable
yields a pointer to a valid address in memory.
Upvotes: 5
Reputation: 39354
It usually doesn't matter what the architecture is because, for a large majority of CPUs in use, addressable locations are in units of byte
s.
As @Caramiriel says, the long strip of paper
is made out of a series of bytes.
Sometimes you deal with them in larger chunks, say a uint32_t
deals with 4 bytes in one go.
When you get to struct
s or objects, these deal with larger chunks of memory, or multiple chunks of memory so that you don't have to know the details.
However, I think that the C
language, and therefore C++
, can be ported to a wide variety of architectures where the smallest addressable unit of memory could be larger (or smaller) that one byte.
Upvotes: 5