size of implementation
#include<stdio.h> #define my_sizeof(type) (char *)(&type+1)-(char*)(&type) int main() { double x; printf("%ld", my_sizeof(x)); getchar(); return 0; }
#include <assert.h> #include <string.h> #include <sys/types.h> #include <unistd.h> void *malloc(size_t size) { void *p = sbrk(0); void *request = sbrk(size); if (request == (void*) -1) { return NULL; // sbrk failed. } else { assert(p == request); // Not thread safe. return p; } }
malloc(0) :
alloc(0)
could returnNULL
or a valid pointer that may not be dereferenced. In either case, it's perfectly valid to callfree()
on it.
// Copies "numBytes" bytes from address "from" to address "to" void * memcpy(void *to, const void *from, size_t numBytes);
// A C implementation of memcpy()
#include<stdio.h>
#include<string.h>
void myMemCpy(void *dest, void *src, size_t n)
{
// Typecast src and dest addresses to (char *)
char *csrc = (char *)src;
char *cdest = (char *)dest;
// Copy contents of src[] to dest[]
for (int i=0; i<n; i++)
cdest[i] = csrc[i];
}
// Driver program
int main()
{
char csrc[] = "GeeksforGeeks";
char cdest[100];
myMemCpy(cdest, csrc, strlen(csrc)+1);
printf("Copied string is %s", cdest);
int isrc[] = {10, 20, 30, 40, 50};
int n = sizeof(isrc)/sizeof(isrc[0]);
int idest[n], i;
myMemCpy(idest, isrc, sizeof(isrc));
printf("\nCopied array is ");
for (i=0; i<n; i++)
printf("%d ", idest[i]);
return 0;
}
// Copies "numBytes" bytes from address "from" to address "to" void * memmove(void *to, const void *from, size_t numBytes);
//C++ program to demonstrate implementation of memmove()
#include<stdio.h>
#include<string.h>
// A function to copy block of 'n' bytes from source
// address 'src' to destination address 'dest'.
void myMemMove(void *dest, void *src, size_t n)
{
// Typecast src and dest addresses to (char *)
char *csrc = (char *)src;
char *cdest = (char *)dest;
// Create a temporary array to hold data of src
char *temp = new char[n];
// Copy data from csrc[] to temp[]
for (int i=0; i<n; i++)
temp[i] = csrc[i];
// Copy data from temp[] to cdest[]
for (int i=0; i<n; i++)
cdest[i] = temp[i];
delete [] temp;
}
// Driver program
int main()
{
char csrc[100] = "Geeksfor";
myMemMove(csrc+5, csrc, strlen(csrc)+1);
printf("%s", csrc);
return 0;
}
void *memset(void *ptr, int x, size_t n);void *my_memset(void *s, int c, unsigned int len)
// Sample program to show that memcpy() can lose data.
#include <stdio.h>
#include <string.h>
int main()
{
char csrc[100] = "Geeksfor";
memcpy(csrc+5, csrc, strlen(csrc)+1);
printf("%s", csrc);
return 0;
}
The Difference
The difference between memcpy
and memmove
is simple: when the source and destination blocks of memory overlap (for example, if they are the same), memmove
works, but memcpy
‘s behavior is undefined. It might work. It might crash. It might corrupt data. It might behave differently during debugging.
memmove
is safer.
memcpy
can be faster, and usually is. There are less restrictions on it’s implementation, so more can be done to optimize it. But not necessarily a lot more — in fact, it could even be slower then memmove
, and sometimes this is the case. On some systems, memcpy
may just be memmove
.
Faster
So how much faster can memcpy
be then memmove
? They both take O(N) time to copy N bytes of data. So in some computer-science circles, memcpy
wouldn’t be considered faster then memmove
.
Ref: https://vgable.com/blog/2008/05/24/memcopy-memmove-and-speed-over-safety/
Example#
A wide variety of standard library functions have among their effects copying byte sequences from one memory region to another. Most of these functions have undefined behavior when the source and destination regions overlap.
For example, this ...
#include <string.h> /* for memcpy() */
char str[19] = "This is an example";
memcpy(str + 7, str, 10);
... attempts to copy 10 bytes where the source and destination memory areas overlap by three bytes. To visualize:
overlapping area
|
_ _
| |
v v
T h i s i s a n e x a m p l e \0
^ ^
| |
| destination
|
source
Because of the overlap, the resulting behavior is undefined.
Among the standard library functions with a limitation of this kind are memcpy()
, strcpy()
, strcat()
, sprintf()
, and sscanf()
. The standard says of these and several other functions:
If copying takes place between objects that overlap, the behavior is undefined.
The memmove()
function is the principal exception to this rule. Its definition specifies that the function behaves as if the source data were first copied into a temporary buffer and then written to the destination address. There is no exception for overlapping source and destination regions, nor any need for one, so memmove()
has well-defined behavior in such cases.
Ref: https://riptutorial.com/c/example/2150/copying-overlapping-memory
Our OWN malloc:
copied from here:
https://danluu.com/malloc-tutorial/
Let’s write a malloc and see how it works with existing programs!
This tutorial is going to assume that you know what pointers are, and that you know enough C to know that
*ptr
dereferences a pointer, ptr->foo
means (*ptr).foo
, that malloc is used to dynamically allocate space, and that you’re familiar with the concept of a linked list. For a basic intro to C, Pointers on C is one of my favorite books. If you want to look at all of this code at once, it’s available here.Preliminaries aside, malloc’s function signature is
void *malloc(size_t size);
It takes as input a number of bytes and returns a pointer to a block of memory of that size.There are a number of ways we can implement this. We’re going to arbitrarily choose to use the sbrk syscall. The OS reserves stack and heap space for processes and sbrk lets us manipulate the heap.
sbrk(0)
returns a pointer to the current top of the heap. sbrk(foo)
increments the heap size by foo
and returns a pointer to the previous top of the heap.If we want to implement a really simple malloc, we can do something like
#include <assert.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
void *malloc(size_t size) {
void *p = sbrk(0);
void *request = sbrk(size);
if (request == (void*) -1) {
return NULL; // sbrk failed.
} else {
assert(p == request); // Not thread safe.
return p;
}
}
When a program asks malloc for space, malloc asks sbrk to increment the heap size and returns a pointer to the start of the new region on the heap. This is missing a technicality, that malloc(0)
should either return NULL
or another pointer that can be passed to free without causing havoc, but it basically works.But speaking of free, how does free work? Free’s prototype is
void free(void *ptr);
When free is passed a pointer that was previously returned from malloc, it’s supposed to free the space. But given a pointer to something allocated by our malloc, we have no idea what size block is associated with it. Where do we store that? If we had a working malloc, we could malloc some space and store it there, but we’re going to run into trouble if we need to call malloc to reserve space each time we call malloc to reserve space.A common trick to work around this is to store meta-information about a memory region in some space that we squirrel away just below the pointer that we return. Say the top of the heap is currently at
0x1000
and we ask for 0x400
bytes. Our current malloc will request 0x400
bytes from sbrk
and return a pointer to 0x1000
. If we instead save, say, 0x10
bytes to store information about the block, our malloc would request 0x410
bytes from sbrk
and return a pointer to 0x1010
, hiding our 0x10
byte block of meta-information from the code that’s calling malloc.our own sizeof:
#define my_sizeof(type) (char *)(&type+1)-(char*)(&type) int main() { double x; printf ( "%d" , my_sizeof(x)); getchar (); return 0; } |
No comments:
Post a Comment