Understanding memcpy
Solution 1
A few problems with your code as it stands:
- You copy 4 bytes, but the destination is type
int
. Sinceint
is not guaranteed to be any particular size, you need to make sure that it is at least 4 bytes long before you do that sort ofmemcpy
. -
memcpy
works on the byte level, but integers are a series of bytes. Depending on your target architecture, the bytes within an integer may be arranged differently (big-endian, little-endian, etc). Usingmemcpy
on integers may or may not do what you expect. It's best to use byte arrays when learning howmemcpy
and friends work. - Your second
memcpy
usespB+1
as the target. This doesn't advance the pointer one byte, it advances it bysizeof(*pB)
bytes. In this case, that leaves it pointing to an invalid address (past the end of the variable). This call tomemcpy
will corrupt random memory, which can crash your program or cause unpredictable results.
Solution 2
I don't think memcpy()
is designed for what you want. In general, you would use memcpy()
to copy one or more whole objects (where an object might be an int, a char, a long long, etc.)
int a[4] = { 1, 2, 3, 4 };
int b[3];
int c[5] = { 0 };
::memcpy(b, a, 3 * sizeof(int)); // b is { 1, 2, 3 }
::memcpy(c+2, b, 3 * sizeof(int)); // c is { 0, 0, 1, 2, 3 }
c+2 is not "c + 2 bytes". It is "c + 2 ints" (8 bytes on a Win32/x86 system).
You can access the individual bytes by casting to a char or unsigned char pointer, but I don't recommend that unless you really understand what you're doing as there are many pitfalls.
unsigned x = 0;
unsigned char *px = reinterpret_cast<unsigned char *>(&x);
px[0] = 0xFF;
px[2] = 0xAA;
One of the dangers here is that you are assuming knowledge about how the computer stores an integer. On an x86 system, x will be 0x00AA00FF but on a Sun Sparc system it will be 0xFF00AA00.
if you need to set parts of an integer it is often better to use "or" and "shift".
x = (0xFF<<24) | (0xAA<<8);
will give you 0xFF00AA00 on any architecture. 0xFF<<24 shifts the value 0xFF by 24 bits to the left, making 0xFF000000. 0xAA<<8 shifts the value 0xAA by 8 bits to the left, making 0x0000AA00.
We "or" them together, giving 0xFF00AA00.
Solution 3
Look into pointer arithmetic: http://www.cs.umd.edu/class/sum2003/cmsc311/Notes/BitOp/pointer.html . Adding a value to a pointer actually incrememnts by that many units of whatever size you're dealing with.
Greg G
Updated on August 03, 2022Comments
-
Greg G almost 2 years
int a = 10; int* pA = &a; long long b = 200; long long* pB = &b; memcpy (pB,pA,4); memcpy (pB+1,pA,4); cout<<"I'm a memcpy!: "<<*(pB)<<endl;
I'm doing some tests with memcpy to teach myself how memory works. What I am trying to do is make b = to "1010". I can copy the value from a to b, but then I try to offset the memory by 1 byte and write another 10 but it doesn't work it only outputs "10".
What would I need to do to get a value of 1010?
-
Greg G about 12 yearsCool I learned a lot. I do have one question though, you say that an int isnt' garanteed to take up 4bytes...I thought it was? Is 4bytes just the limit that it can take up? When I create an int and intilize it to a value does it only use the number of bits, or bytes nesccary?
-
Michael J about 12 yearsInt size is machine and compiler dependent. I can't think of a modern compiler/CPU that don't have 4-byte ints, but I can think of lots of old ones. It is likely that future machines will have bigger ints. When we get 128-bit machines, ints will probably be 64 bits (8-bytes).
-
bta about 12 years@user1372122- The basic types
short
,int
,long
, andlong long
don't have standardized sizes.int
has a fixed size, but that fixed size varies from platform to platform (for example between x86 and MIPS CPUs, or between 32-bit and 64-bit OSes). There are datatypes, however, that are guaranteed to have specific sizes. They have names likeuint32_t
andint16_t
(for a 32-bit unsigned integer and 16-bit signed integer, respectively) and they come fromstdint.h
. -
user207421 over 6 yearsYou appear to be commenting on this answer. You should make that clear. Your own answer assumes an x86 recent enough to have SIMD instructions.