I wanted to see if restrict
would prevent memcpy
from accessing overlapping memory.
The memcpy
function copies n bytes from memory area src to memory area dest directly. The memory areas should not overlap. memmove
uses a buffer so there is no risk of overlapping memory.
The restrict
qualifier says that for the lifetime of the pointer, only the pointer itself or a value directly from it (such as pointer + n
) will have access to the data of that object. If the declaration of intent is not followed and the object is accessed by an independent pointer, this will result in undefined behavior.
#include <stdio.h>
#include <string.h>
#define SIZE 30
int main ()
{
char *restrict itself;
itself = malloc(SIZE);
strcpy(itself, "Does restrict stop undefined behavior?");
printf("%d\n", &itself);
memcpy(itself, itself, SIZE);
puts(itself);
printf("%d\n", &itself);
memcpy(itself-14, itself, SIZE); //intentionally trying to access restricted memory
puts(itself);
printf("%d\n", &itself);
return (0);
}
Output ()
Address of itself: 12345
Does restrict stop undefined behavior?
Address of itself: 12345
stop undefined bop undefined behavior?
Address of itself: 12345
Does memcpy
use an independent pointer? Because the output definitely shows undefined behavior and restrict
doesn't prevent access to overlapping memory with memcpy
.
I'm assuming memcpy
has a performance advantage since it copies data directly while memmove
uses a buffer. But with modern computers, should I disregard this potentially better performance and always use memmove
since it guarantees no overlap?
The
restrict
keyword is a hint provided to the compiler to allow the generation of code, telling the compiler it should not be bothered with the possibility of pointer aliasing (two different named pointers accessing the same address).In a function that takes
restrict
pointers, the compiler understands that writing to one will not impact the other. When copying from location A to location B, this means it can safely change this code :Into this sequence:
These two sequences are identical only if A and B do not overlap and the compiler will not optimize into the second one unless you used
restrict
(or unless it can guess from the context that it is safe to do so).If you end up providing aliased pointer to a function that does not expect them, the compiler may be able to warn you at compile time but there is no guarantee that it will. But you really should not expect an error at compile time - instead you should see it as a permission you grant to the compiler when it generates the assembly from your code.
Answering your question about performance - if you know for sure that there is no overlap in your pointers, use
memcpy
. If you don't, usememmove
.memmove
will generally check if there is an overlap and end up usingmemcpy
if there isn't, but you pay for the check.