Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

C and C++ pointers often become address-like values in machine code, but they are not unrestricted integers. The language treats them as values that designate objects or functions under rules about type, lifetime, alignment, and bounds. Operating systems and hardware add another layer: a process uses virtual addresses, while CPUs and devices may use different physical or bus addresses. To access device registers safely, software needs platform-specific mapping and I/O operations—not just a pointer cast or volatile.

What a pointer means in C and C++

A pointer is a typed value used to refer to an object or function. In real programs, implementations commonly represent pointers with address-like bits and translate pointer operations into machine instructions. That practical resemblance does not make a pointer an integer with permission to access any location whose numeric address seems right.

The language model is about objects and valid operations. A pointer can designate an object or function, designate the position one past an array object, be null, or be invalid. The C++ reference on pointers summarizes these categories; C’s object model likewise constrains storage and typed access. A 2018 C committee discussion paper, WG14 N2311, explores pointer provenance—the idea that a pointer’s validity may depend on how it was derived, not only on its numeric address. It is useful context, not normative final-standard wording.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

What taking an address and dereferencing do

Taking an address

In int x = 7; int *p = &x; int y = *p;, &x produces a pointer designating the object x. The declaration int *p says that p is a pointer to int; it does not grant access to every address that could be interpreted as an integer.

Dereferencing

*p is an expression that designates the pointed-to object. In this example, evaluating it to initialize y obtains the value stored in x. As the GNU C Language Manual’s Pointers section puts it, “The unary operator ‘*’ gets the data that a pointer points to—this is called dereferencing the pointer.” That description assumes the pointer is valid for the operation. It does not mean every dereference must cause a physical RAM read: a compiler may optimize or transform operations while preserving the behavior required by the language.

Validity, lifetime, alignment, and bounds

A null pointer, a dangling pointer to an object whose lifetime has ended, or a pointer that is misaligned or otherwise invalid cannot safely be dereferenced. The relevant rules depend on the operation and type. Pointer arithmetic is constrained to the relevant array object and its one-past position; the one-past pointer may be formed for permitted comparisons and arithmetic, but it does not designate an element that can be accessed. Numeric address coincidence alone does not establish that a pointer validly designates an object.

For C++, see the reference on pointer arithmetic and pointer values; for C, see the references on pointers and objects and effective type. These are technical summaries, not substitutes for the applicable language standard.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Why a process pointer is not necessarily a hardware address

On systems with virtual memory, a process normally works with virtual addresses. The CPU’s translation machinery maps those addresses to CPU physical memory locations. Devices may use a third address domain, such as bus or DMA addresses. An IOMMU or platform-specific bus mapping can make a device-visible address differ from both the CPU virtual address and the CPU physical address.

Linux’s 5.10 address-mapping documentation explicitly distinguishes CPU virtual, CPU physical, and bus addresses, and warns against assuming they can be converted with a simple numeric shortcut. The document includes older conversion interfaces that it labels superseded; use it for the conceptual distinction, not as current driver instructions. DMA setup must use the appropriate operating-system and platform interfaces for the target kernel and device.

How device registers are accessed

Memory-mapped I/O

With memory-mapped I/O (MMIO), a device exposes a register window that the CPU can access through load/store-like operations. The address range must first be discovered and mapped through the operating system’s interface. It is not enough to take a number from a device manual and cast it to an ordinary C or C++ pointer.

For Linux kernel drivers, the relevant family includes ioremap and typed accessors such as readX/writeX or ioreadX/iowriteX. Exact APIs and guarantees depend on kernel version and architecture. The Linux kernel’s device I/O documentation explains that a device physical address should be mapped to a CPU virtual address before access. These kernel facilities are not portable hosted C or C++ interfaces; user-space applications should use the supported OS or device-driver API for their platform.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Ordering and completion

Device interactions can depend on the order of reads and writes. The compiler, CPU, caches, and interconnect may transform, combine, cache, or defer operations in ways that are valid for ordinary memory but unsuitable for a device protocol. Correct ordering requires the right mapping attributes, accessor, and any required barrier for the architecture and device. A memory barrier is not a universal substitute for a proper mapping and accessor, and a barrier intended only for synchronization among CPUs may not provide the needed device-ordering guarantee.

Best Value

The Linux kernel’s version 6.4 “Accessing Devices” documentation states: “Inside of the Linux kernel, I/O should be done through the appropriate accessor routines – such as inb() or writel() – which know how to make such accesses appropriately sequential.” The rule is about kernel driver practice; the specific guarantee depends on the accessor and platform.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

What volatile does—and does not do

In C and C++, volatile affects how the compiler treats certain accesses to volatile objects. It is not a general-purpose hardware synchronization feature. By itself, it does not establish CPU ordering, cache coherency, bus completion, atomicity, or a portable MMIO interface.

That distinction matters because “the compiler emits an access” and “the device observes that access in the required order” are different claims. Linux kernel guidance directs driver code to use the appropriate I/O accessor routines; direct access through ordinary pointers does not work across all architectures. For a device, follow its operating system’s documented interfaces and the device’s ordering requirements rather than relying on volatile alone.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Keep the two layers separate

Question C/C++ language layer Platform and hardware layer
What does the pointer designate? An object or function, subject to language rules for type, lifetime, alignment, and bounds. An implementation may represent it as an address-like value and use CPU instructions to access storage.
What does an address identify? A pointer value’s validity is governed by the language; numeric equality alone does not prove a valid object access. Virtual, CPU physical, and device bus/DMA addresses may be distinct and require translation or mapping.
How is a device register accessed? Pointer syntax and volatile do not define a portable MMIO interface. Use the OS’s mapping and I/O-accessor facilities, with platform-appropriate ordering.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.