简体   繁体   English

将整数复制到缓冲区 memcpy C++

[英]Copying an integer to a Buffer memcpy C++

Basically I would like to store the address of a pointer in a buffer.基本上我想将指针的地址存储在缓冲区中。 Don't ask me why不要问我为什么

char * buff = "myBuff";
char * myData = (char*)malloc(sizeof(char*));
int addressOfArgTwo = (unsigned int)buff;
memcpy(myData, &addressOfArgTwo, sizeof(char*));

cout << "Int Val: " << addressOfArgTwo << endl;
cout << "Address in buffer:" << (unsigned int)*myData << endl;

I can't see why the above code doesn't work.我不明白为什么上面的代码不起作用。 It outputs:它输出:

Int Val: 4472832
Address in buffer:0

When the Int Val & Address in Buffer should be the same.当 Buffer 中的 Int Val & Address 应该相同时。 thanks谢谢

You dereference a char *, resulting in a char, and then cast that 1-byte char to an int, not the entire 4 bytes of address (if this is a 32-bit machine, 8 bytes on 64-bit).您取消引用一个 char *,生成一个 char,然后将该 1 字节的 char 转换为一个 int,而不是整个 4 字节的地址(如果这是 32 位机器,则为 64 位机器上的 8 个字节)。 4472832 is 444000 in hexadecimal. 4472832 是十六进制的 444000。 On a little-endian machine, you grab that last 00.在小端机器上,您获取最后一个 00。

*((unsigned int*)myData)

should result in the correct number being displayed.应该会显示正确的数字。

This is generally dangerous:这通常是危险的:

 *((unsigned int*)myData)

Intel IA-32 (that everyone's used to) supports unaligned accesses, but some other architectures don't. Intel IA-32(每个人都习惯了)支持未对齐访问,但其他一些架构不支持。 They require variables to be aligned (8-bit data on 1-byte boundaries, 16-bit data on 2-byte boundaries, and 32-bit data on 4-byte boundaries).它们需要对齐变量(1 字节边界上的 8 位数据、2 字节边界上的 16 位数据和 4 字节边界上的 32 位数据)。 On an architecture that requires alignment, an unaligned access will either return corrupt data or throw a CPU exception.在需要对齐的架构上,未对齐的访问将返回损坏的数据或引发 CPU 异常。 I've seen it cause a bug in real life at a past job, a subtle bug that caused file system corruption because of the disk driver that came with a software package we were using (on an embedded platform).我在过去的工作中看到它导致现实生活中的错误,这是一个微妙的错误,由于我们使用的软件包附带的磁盘驱动程序(在嵌入式平台上)导致文件系统损坏。

In this isolated case, you can see the address of myData came from malloc(), which should mean it's suitably aligned for all types of pointers, but casting a smaller pointer to a larger pointer is generally a dangerous practice if you don't know where the pointer came from.在这种孤立的情况下,您可以看到 myData 的地址来自 malloc(),这应该意味着它适合所有类型的指针对齐,但是如果您不知道,将较小的指针转换为较大的指针通常是一种危险的做法指针来自哪里。

The safe way to extract a 32-bit integer from an arbitrary memory location is to declare a temporary 32-bit integer and perform a copy to it, treating the source memory as a raw character array:从任意内存位置提取 32 位整数的安全方法是声明一个临时 32 位整数并对其执行复制,将源内存视为原始字符数组:

unsigned int GetUnalignedLittleEndianUInt32(void *address)
{
    unsigned char *uc_address = (unsigned char *)address;
    return (
        (uc_address[3] << 24) |
        (uc_address[2] << 16) |
        (uc_address[1] << 8) |
        uc_address[0]
    );
}

or more generally (with some function call overhead):或更一般地(有一些函数调用开销):

unsigned int GetUnalignedUInt32(void *address)
{
    unsigned int value;
    memcpy(&value, address, sizeof(value));
    return value;
}

which is actually just the reverse of the memcpy() you did to get the pointer there in the first place.这实际上与您最初为获取指针所做的 memcpy() 相反。

Although, treating the pointer as an int:虽然,将指针视为 int:

int addressOfArgTwo = (unsigned int)buff;

is also dangerous, if you're moving between 32-bit and 64-bit architectures, as Michael pointed out.正如迈克尔指出的那样,如果您在 32 位和 64 位架构之间移动,这也是危险的。 Pointers aren't always 32-bit integers.指针并不总是 32 位整数。 Consider using a typedef that you can later change.考虑使用以后可以更改的 typedef。 The convention on Linux is for a pointer to be the same size as a long. Linux 上的约定是指针的大小与 long 相同。 On Windows, there are typedefs INT_PTR, UINT_PTR, LONG_PTR, and ULONG_PTR.在 Windows 上,有类型定义 INT_PTR、UINT_PTR、LONG_PTR 和 ULONG_PTR。

So, I would finally suggest (on Windows anyway):所以,我最终建议(无论如何在 Windows 上):

ULONG_PTR GetAddressAtAddress(void *address)
{
    ULONG_PTR value;
    memcpy(&value, address, sizeof(value));
    return value;
}

Instead of:代替:

(int)*myData 

it should be:它应该是:

*((int*)myData)

正如迈克尔所说,这条线应该是

cout << "Address in buffer:" << *((unsigned int*)myData) << endl

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM