Unlocking Faster Memory Copy with C99’s `restrict` Keyword
Speed up your C memory copy by using the C99 <code>restrict</code> keyword. Learn how it works, see a concrete example, understand trade‑offs, and validate the performance gains in a few steps.
22 Mar 2026, 22:15 UTC

Problem: Slow, Generic Memory Copy
When you copy large blocks of data in C, the compiler must assume that the source and destination could overlap. That conservative assumption forces the generated code to avoid aggressive optimizations like vectorization or loop unrolling, even when the programmer knows the buffers are distinct.
Thesis: Use `restrict` to Tell the Compiler It’s Safe
The C99 restrict keyword is a compile‑time hint that a pointer is the only means to access the object it points to during the lifetime of the pointer. When both source and destination pointers in a copy routine are declared restrict, the compiler can safely assume no aliasing and emit faster code.
How `restrict` Works
Alias analysis is a core part of modern optimizers. By default, the optimizer must consider that two pointers might refer to overlapping memory, which restricts transformations. Declaring a pointer as restrict removes that possibility for the scope of the pointer, allowing:
- Vectorized loads/stores (e.g.,
vmovdquon x86) - Loop unrolling and software pipelining
- Elimination of redundant memory accesses
These changes are purely compile‑time; no runtime cost is added.
Syntax Recap
void copy_restrict(void *restrict dst, const void *restrict src, size_t n);
The restrict qualifier applies only to pointer objects. It does not affect arrays declared on the stack or global data.
Concrete Example: A Custom `memcpy`
Below is a minimal copy routine that benefits from restrict. The function copies n bytes from src to dst using a simple loop. With restrict, GCC on x86‑64 can vectorize the loop into 64‑byte chunks.
#include <stddef.h>
void copy_restrict(void *restrict dst, const void *restrict src, size_t n) {
unsigned char *d = (unsigned char *)dst;
const unsigned char *s = (const unsigned char *)src;
for (size_t i = 0; i < n; ++i) {
d[i] = s[i];
}
}
Compile with optimizations:
gcc -O2 -march=native -S copy.c -o copy.s
Inspecting copy.s reveals vector instructions. If you remove the restrict qualifiers, the assembly will lack these optimizations.
Trade‑Offs and Limitations
- Undefined Behavior on Overlap: If
dstandsrcoverlap, callingcopy_restrictresults in UB. Usememmovefor overlapping regions. - Compiler Support: All mainstream compilers (GCC, Clang, MSVC) support
restrictin C99 mode, but some older toolchains may ignore it. - Optimization Level: The benefit appears only when optimizations are enabled (e.g.,
-O2or higher). With-O0, the compiler will not vectorize regardless ofrestrict. - Threading Considerations:
restrictapplies per thread. Shared data accessed by multiple threads still requires proper synchronization.
Verification Steps
- Write two versions of
copy– one withrestrict, one without. - Compile each with
-O2 -march=native -Sand compare the assembly for vector instructions. - Benchmark both functions copying 10 MB of data in a tight loop using
timeorperf. A typical speedup is 10–30% on modern CPUs. - Run a test where
dstandsrcoverlap. Therestrictversion should produce incorrect output, confirming that UB occurs. - Compile with
-fno-strict-aliasingto see that the optimizer no longer assumes alias freedom and the performance gap disappears.
Actionable Closing
When you write high‑performance copy routines or work with large data buffers, consider adding restrict to the pointer parameters. Verify that the buffers are non‑overlapping before use. With a quick compile‑time check and a small benchmark, you can confirm the benefit and avoid the pitfalls of undefined behavior.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.