【问题标题】:Does memcpy depend on the type of the source and destination pointers?memcpy 是否取决于源指针和目标指针的类型?
【发布时间】:2019-11-06 12:08:39
【问题描述】:

这段代码,

uint32_t length;
BYTE* message;
printf("Inspecting message with length %d and contents: ", length);
for(int i=0;i<length;i++)
    printf("%d ", message[i]);
printf("\n");
....
char* outbuff;
outbuff = (char*) malloc(sizeof(char) * length + sizeof(int));
uint32_t data_length = htonl(length);
memcpy(outbuff, &data_length , sizeof(int));
memcpy(outbuff + sizeof(uint32_t), message, length);

printf("Sending  outbuff over network with length %d and contents: ", length);
for(int i=0;i<length;i++)
    printf("%d ", outbuff[i]);
printf("\n");

不会忠实地将数据从消息和长度复制到输出缓冲区。但是一旦我将输出缓冲区的类型从 char* 更改为 BYTE*,它就可以正常工作了。

知道它为什么会这样吗? documentation 在这件事上没有帮助。

EDIT.1:将&amp;length 更改为&amp;data_length。我手动输入代码而不是在 SX 中复制。

EDIT.2:打印出 BYTE 数组的代码。

【问题讨论】:

  • 你怎么知道它没有“忠实地从消息和长度复制数据”?您如何验证复制的内容?
  • 这段代码很乱。当长度为uint32_t 时为什么要sizeof(int)?为什么分配给data_length却复制length
  • 一个潜在的不相关错误是您复制了不一定是 int 的对象的 sizeof(int) 字节。复制 uint32_t 时,应复制 sizeof(uint32_t) 字节。
  • (1) sizeof(char) 始终为 1,因此可以省略。 (2) @eerorika 是对的:在整个长度中使用uint32_t,尤其是sizeof:不能保证int 是32 位的。 (3) 无论第一个指针的类型是什么,memcpy() 都会起作用。 (但在添加时必须小心,如 outbuff + sizeof(uint32_t),因为如果它指向大小大于 1 的类型,您将到达错误的地址。这在此处无关紧要,因为 BYTE 通常是unsigned char 的 typedef。)
  • @Someprogrammerdude Windows 中有一个BYTE,是的。这个可能来自别的东西。请特别注意linux 标签。关键是我们不知道,猜测会适得其反。

标签: c++ linux memcpy


【解决方案1】:

我正在回答我刚刚自己编辑的新标题问题 ;-)。

答案很简单不。

您问题中的链接显示memcpy()被声明为void *memcpy(void *dest, const void *src, size_t n);。两个指针参数都是空指针。

标准草案将任何指向void * 的指针的转换列为标准转换(不需要显式转换)。 Specifically, it states(我强调):

“指向 cv T 的指针”类型的纯右值,其中 T 是对象类型,可以转换为“指向 cv void 的指针”类型的纯右值。 指针值([basic.compound])在这个转换中没有改变。

这意味着你扔给它的任何对象指针都将在 memcpy 看到它之前被转换为数字相同的 void 指针,因此被同等对待。

你的问题一定出在其他地方。

【讨论】:

    【解决方案2】:

    只是在这里猜测,但我认为您的意思是使用网络字节顺序,因此 data_length 属性,但之后您仍然将 length 放入缓冲区中。

    你的

    memcpy(outbuff, &length, sizeof(int));
    

    应该读过

    memcpy(outbuff, &data_length, sizeof(uint32_t));
    

    另外,您似乎在交替使用 intuint32_t。它们不是,即使在大小匹配的平台上,一个已签名而另一个未签名。

    【讨论】:

    • 是的!谢谢你的建议。我确实复制了 data_length 而不是长度。正如我的问题的编辑中所解释的那样,这是一个错字。
    • 我必须坚持彼得已经向您提出的要求,即提供一个实际发生的最小示例......据我所知,以及其他人所表达的,这应该现在工作......提供一个它不起作用的最小示例,错误可能在您的网络代码或其他地方
    • 我已经编辑了我的问题以满足您的要求。在我开始通过网络发送数据之前,数组元素的乱码就发生了很多。
    • 不,@Vineet,你没有。您已经获得了有关如何制作minimal reproducible example 的说明的链接。请跟随它,阅读它们,然后去做!
    【解决方案3】:

    BYTE*char* 执行memcpy() 可能会导致char 的范围环绕,即-127 到127,因为BYTE 从0 到255 是无符号的。

    例如,假设我们有:

    BYTE uchArr[] = {12, 129, 250};
    BYTE * ptr_uchArr = (BYTE*) malloc (sizeof(BYTE)*3);
    memcpy(ptr_uchArr, &uchArr, sizeof(BYTE)*3);
    //ptr_uchArr shall be {12, 129, 250} as intended...
    

    现在我们要执行 memcpy()BYTE*char*

    char * ptr_chArr = (char*) malloc (sizeof(char)*3);
    memcpy(ptr_chArr, ptr_uchArr, sizeof(BYTE)*3);
    //ptr_chArr shall be {12, -127, -6} as a result of wrap around...
    

    如果我们执行相反的操作,即从char*BYTE*memcpy()

    memcpy(ptr_uchArr, ptr_chArr, sizeof(BYTE)*3);
    //ptr_uchArr shall still be {12, 129, 250} as intended again as a result of wrap around...
    

    【讨论】:

    • 不,memcpy 复制字节中的数据。就是这样。您以后如何解释这些字节对memcpy 来说并不重要。但是,当目标类型不是 OP 想要的类型时,所述解释可能存在问题。
    • 感谢澄清,我同意!!
    猜你喜欢
    • 2014-02-19
    • 2011-07-27
    • 1970-01-01
    • 2021-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多