How to copy a repeating pattern to the memory buffer?

I want to write a repeating byte pattern to a memory block. My idea is to write the first sample template and then copy it to the rest of the buffer. For example, if I start with this:

ptr: 123400000000 

After that, I want it to look like this:

 ptr: 123412341234 

I thought I could use memcpy to write to intersecting areas, for example:

 memcpy(ptr + 4, ptr, 8); 

The standard does not indicate in what order the copying will occur, therefore, if some implementation forces it to copy in the reverse order, it can give different results:

 ptr: 123412340000 

or even combined results.

Is there a workaround that allows me to use memcpy , or do I need to implement my own loop? Note that I cannot use memmove because it does exactly what I am trying to avoid; he will do ptr 123412340000 , and I want 123412341234 .

I am programming for Mac / iPhone (clang compiler), but a generic answer would be good too.

+6
source share
6 answers

There is no standard function for repeating a byte pattern over a range of memory. You can use the memset_pattern* family of functions to get fixed-size templates; if you need a size that you need to change, you have to roll it yourself.

 // fills the 12 first bytes at `ptr` with the 4 first bytes of `ptr` memset_pattern4(ptr, ptr, 12); 

Remember that memset_pattern4 , memset_pattern8 and memset_pattern16 only exist on Mac OS / iOS, so do not use them for cross-platform development.

Otherwise, moving (cross-platform) a function that makes a copy of byte by byte is quite simple.

 void byte_copy(void* into, void* from, size_t size) { for (size_t i = 0; i < size; i++) into[i] = from[i]; } 
+5
source

This is what kernel.org says:

The memcpy () function copies n bytes from the src memory region to the Dest memory region. Areas of memory should not overlap . Use memmove (3) if memory areas overlap.

Here is what MSDN says:

If the source and destination overlap, memcpy's behavior is undefined . Use memmove to handle overlapping regions.

+5
source

The C ++ answer for all platforms is std :: fill_n (destination, elementRepeats, elementValue).

What did you ask for:

 short val = 0x1234; std::fill_n(ptr, 3, val); 

This will work for val of any type; chars, shorts, ints, int64_t etc.

+2
source

Old answer

You want memmove() . Full description:

Memmove () must copy n bytes from the object pointed to by s2 to the object pointed to by s1. Copying occurs as if n bytes from the object pointed to by s2 are first copied to a temporary array of n bytes that does not overlap the objects pointed to by s1 and s2, and then n bytes from the temporary array are copied to the object, onto which indicates s1.

On the memcpy() page:

If copying occurs between overlapping objects, the behavior is undefined.

In any case, you should use memmove() . This is because the result of using memcpy() not reliable.

Matching bits for the actual question

You are requesting memcpy(ptr + 4, ptr, 8); which says it copies 8 bytes from ptr and puts them in ptr+4 . ptr is 123400000000, the first 8 bytes are 1234000, so it does this:

 Original : 123400000000 Writes : 12340000 Result : 123412340000 

You need to call:

 memcpy(ptr+4, ptr, 4); memcpy(ptr+8, ptr, 4); 

To achieve what you need. Or implement the equivalent. This should do it, but it has not been tested and is equivalent to memcpy; you need to either add an extra temporary buffer, or use two non-overlapping memory areas.

 void memexpand(void* result, const void* start, const uint64_t cycle, const uint64_t limit) { uint64_t count = 0; uint8_t* source = start; uint8_t* dest = result; while ( count < limit ) { *dest = *source; dest++; count++; if ( count % cycle == 0 ) { source = start; } else { source++; } } } 
0
source

You can do this by copying once and then memcpy everything, to copy to the following bytes and repeat this, this is better understood in the code:

 void block_memset(void *destination, const void *source, size_t source_size, size_t repeats) { memcpy(destination,source,source_size); for (size_t i = 1; i < repeats; i += i) memcpy(destination + i,destination,source_size * (min(i,repeats - i))); } 

I tested; it works as fast as a regular memset for a large number of repeats , and source_size quite dynamic, without source_size too much.

0
source

Why not just allocate an 8-byte buffer, move it there, and then move it back to where you want? (As @cnicutar says, you should not have overlapping address spaces for memcpy.)

-1
source

Source: https://habr.com/ru/post/890368/


All Articles