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;
}
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
memcpyfor type punning. On Arm64 or x86_64, they often optimize it into a single register move (ldr/strormov), meaning zero function call overhead.
5. Warning & Pro-Tips
-
The Overlap Trap:
memcpyassumes the source and destination do NOT overlap. If they might, always usememmove. -
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-aliasingused to relax these rules globally.
Top comments (1)
Good Point: Using
memcpyon 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
intbecomes 64 bit.