Is the variable address in C the real address in the RAM of the computer?

In C, when you get the address of a variable, is it the address that really exists in the RAM of the computer or just the address in fake memory in the C compiler (if that works)? Can you explain in terms of the laity?

+5
source share
4 answers

Yes and no. When you take the address of a variable and perform some operations on it (provided that the compiler does not optimize it), it will correspond to the address in ram. However, because of virtual memory, the address used in your program is almost certainly not the address of a variable in physical RAM. The kernel reassigns which virtual addresses (what your program sees) refers to those physical addresses (what memory sees), so that different processes can simultaneously be loaded into memory, but not be able to access the memory of others. In addition, your process memory can be unloaded or written to disk if it has not been used recently and / or something else needs more memory and will reboot to a completely different address, but the virtual address will remain the same.

So yes, when you access the pointer, this address corresponds to the address in memory. But this address does not match the actual address in ram, and the address that it matches may change over time.

+2
source

The answer is sorting none.

In general terms, the address of a variable in memory is in the context of the address space of a program.

What distinguishes the way the address space of the program is mapped to the equipment of the host system.

With modern hardware that has a memory management unit (MMU) and operating systems (or device drivers) that use the MMU, the address space of the program is mapped to physical memory, which can consist of RAM or virtual memory, such as a swap file on the hard drive. The operating system uses an MMU to isolate programs from each other (so the two processes cannot access a different address space), and also uses an MMU to support the exchange of data between RAM and swap. An ongoing process cannot even determine where its data resides in physical memory, because the operating system and MMU specifically prevent it. Over time, the operating system and the MMU can transfer the memory used by the program to different areas of RAM or for exchange, but the program cannot detect this, since the operating system and the MMU take care of displaying the address in the program (which never changes as far as the program is concerned ) to the actual address. This covers the latest versions of windows, unix and various real-time operating systems. (These systems also typically provide software access to physical memory, but only for programs running with higher privileges or kernel-mode drivers).

Older hardware did not have an MMU, so operating systems could not provide programs with separate address spaces. In such systems, the address visible by the program had a one-to-one correspondence with the location in the physical memory.

Somewhere between them was equipment that had separate areas of physical memory (for example, provided by individual banks of memory chips). In these systems with support for special drivers, the host system can implement a partial mapping between addresses in the program address space and places in certain areas of physical memory. This is why some target systems and compilers that support them support more than one type of pointer (for example, with names near, far and large) as a compiler extension. In these cases, the pointer may refer to a location in a specific area of ​​memory, and there may be some mapping of values ​​for each type of pointer from the value of the pointer visible by the program to the actual location in the corresponding area of ​​physical memory.

The C compiler is not included in the executable program that it creates (otherwise, to install any firmware, you will also need to install and run the compiler used to create it, or the program will not work). Typically, the compiler no longer works when a program is executed (or at least the program cannot rely on its presence). Therefore, the program cannot access addresses in the address space of the compiler.

In an interpreted environment (for example, C code is interpreted by another program - the interpreter), the interpreter acts as an intermediary between the program and the hardware and processes the mapping between the address space of the program, the address space of the interpreter and physical memory, C translators are relatively rare in practice, compared to instrumental goals that compilers and linkers use.

+1
source

In the case of a multi-process environment where several processes start at the same time, the linker cannot determine the address of the variables at compile time. The reason is simple, if you assign a dedicated address to variables, then you limit the number of processes that can run on your system.

Thus, they assign a virtual address to variables and addresses translated to physical addresses at runtime using the OS and processor. One example of such a system is linux running on an x86 CPU.

In other cases, when there is only one process / application running on the processor, then the linker can assign the actual physical address to the variables. For example: embedded systems that perform dedicated tasks, such as an oven.

0
source

In ancient OSs, the MMU is missing or not used on the target processor (even if the processor allows it).

In this case, physical addresses are used, which are easier to understand, but also annoying, because when debugging the build program or trying to decode the tracking one, you should know where the program was loaded or use posthumous tracing.

Without MMU, you can do very hacked and simple things. The shared memory can be encoded in several lines, you can easily view all the memory, etc.

In modern operating systems , relying on the capabilities of the MMU processor and address translation, the executable files are executed in virtual memory, which is not a problem since they cannot access other executable file memory.

The good side is that if you repeatedly execute / debug the same executable file, you always get the same addresses. Useful for long debugging sessions when you have to restart the debugger many times.

In addition, some languages ​​/ compilers (such as the GNAT Ada compiler) provide address tracing when a program does something illegal. Using addr2line in the executable file, you can get an accurate trace even after the process is complete and memory is freed.

The exception that I know of is Windows shared libraries (DLLs), which almost never load at the same address, as this address is potentially shared between multiple executables. In such cases, for example, post-mortem tracing will be useless since the declared symbol address is offset from the actual trace address.

0
source

Source: https://habr.com/ru/post/1275566/


All Articles