I am trying to port some C Code but I am really stuck cause of the use of memcpy I tried with ctypes (did not work). I am hoping to find a python way of using an equivalent function of memcpy
Any ideas
Here is an example of the C Code I am trying to port
i = l + 5;
t = htons(atoi(port));
memcpy((buf+i), &t, 2);
You almost certainly don't need to call htons
and then copy the 2 bytes into a buffer—see Keith's answer for why.
However, if you do need to do this (maybe you're crafting IP packets to compare to captured wire packets as a test or something?), you can.
First, if you're using a bytearray
(or anything else that meets the writable buffer protocol), you just use normal list
-style slice assignment:
# like C's memcpy(buf+i, foo, 2)
buf[i:i+2] = foo
You don't have that two-byte string foo
; you have a short integer. In C, you can turn that into a pointer to two bytes just by using the &
operator to get its address, but Python can't do that. Fortunately, there's a standard library module called struct
designed for exactly this kind of thing:
t = socket.htons(int(port))
buf[i:i+2] = struct.pack('h', t)
Or, because struct
can handle endianness for you:
t = int(port)
buf[i:i+2] = struct.pack('!h', t)
However, often you don't even need the buffer copying; you can define the entire structure all at once inside struct
. For example, if you're trying to pack an IP address and port into a 6-byte array, you could do this:
buf = bytearray(6)
i = 0
addrbytes = [int(part) for part in addr.split('.')]
buf[i:i+4] = struct.pack('4B', addrbytes[0], addrbytes[1], addrbytes[2], addrbytes[3])
i += 4
portshort = int(port)
buf[i:i+2] = struct.pack('!h', portshort)
But this is much simpler:
addrbytes = [int(part) for part in addr.split('.')]
portshort = int(port)
buf = struct.pack('!4Bh', addrbytes[0], addrbytes[1], addrbytes[2], addrbytes[3], portshort)
I've just defined a structure that's in network order, with four bytes followed by a short, and packed my data into it.
One last thing to mention: If you really want to deal with C-style variables using C-style code, the ctypes module is another option. It's made specifically for interacting with C code, so in general it's pretty low-level (and the only module in the standard library that lets you segfault your code), but it let you build some nice mid-level stuff that looks a little more like C:
class ADDRPORT(ctypes.BigEndianStructure):
_fields_ = [("addr", ctypes.c_char*4),
("port", ctypes.c_short)]
addrport = ADDRPORT(addrbytes, portshort)
Since your C code is progressively filling up a buffer, rather than setting elements of a struct
, this probably isn't what you want. But it's worth being aware of, because it probably will be what you want at some point.