DEV Community

Cover image for memcpy
susanayi
susanayi

Posted on

memcpy

Q: Why is memcpy safer than pointer casting for type punning?

πŸ’‘ Concept in a Nutshell

memcpy is the "Official Copy Machine" of C: It doesn't care if your data is a math book or a cookbook; it only sees "paper" (Bytes) and duplicates them from point A to point B without violating language laws.

1. Life Analogy (The Librarian vs. The Xerox)

Imagine you have a Math Book but you want to read it as a Cookbook.

  • Pointer Casting (*(int*)&f): This is like forcing a Librarian to read a Math book as a Cookbook. The Librarian will get confused because it violates the "Library Classification Rules" (Strict Aliasing).
  • memcpy: This is like putting the Math book into a Xerox machine. The machine doesn't read the words; it just copies the ink onto new paper. Now you have "Cookbook-shaped" paper with "Math-ink" on it. It’s perfectly legal because the Xerox machine is allowed to touch any paper!

2. Code Example

#include <stdio.h>
#include <string.h>

int main() {
    float f = 3.14f;
    int i;

    // "Photocopy" the 4 bytes of f into i
    memcpy(&i, &f, sizeof(int));

    printf("Memory content of float 3.14f = 0x%X\n", i);
    // Output: 0x4048F5C3 (on IEEE 754 systems)

    // It works backwards too!
    int j = 1078523331;
    float g;
    memcpy(&g, &j, sizeof(float));
    printf("Int 1078523331 as float = %f\n", g);
    // Output: 3.140000

    return 0;
}
Enter fullscreen mode Exit fullscreen mode

3. Standard (C99 Clause): 6.5.7

The char* Exception: The C standard allows char* (and unsigned char*) to alias any object type. Since memcpy is defined to operate byte-by-byte, it bypasses the Strict Aliasing Rule.

4. Key Techniques (Why it Works)

  • memcpy: The most robust way to copy bits between types.
  • Compiler Optimization: Modern compilers (GCC/Clang) recognize memcpy for type punning. On Arm64 or x86_64, they often optimize it into a single register move (ldr/str or mov), meaning zero function call overhead.

5. Warning & Pro-Tips

  • The Overlap Trap: memcpy assumes the source and destination do NOT overlap. If they might, always use memmove.
  • Size Matters: Ensure sizeof(dest) >= sizeof(src) to avoid buffer overflows.
  • Compiler Flag: In large projects (like the Linux Kernel), you might see -fno-strict-aliasing used to relax these rules globally.

Top comments (1)

Collapse
 
yairlenga profile image
Yair Lenga

Good Point: Using memcpy on modern compilation, is safer and as performant as the old trick of conversion via union member, which was used in old code to avoid the function call.

Worth mentioning that while for most current architecture (ARM64, X86_64) sizeof(float) = sizeof(int) = 4, this is not guaranteed. Static assert can be added to "future proof" the code - ensure this assumption is true, without introducing any run-time cost. It will cause the compile to fail if/when default int becomes 64 bit.

// C23
static_assert(sizeof(uint32_t) == sizeof(float));

// C11 - gcc<14, clang<19
_Static_assert(sizeof(int) == sizeof(float),
               "uint32_t and float must have same size");
Enter fullscreen mode Exit fullscreen mode