对memcpy和mmap的误解

Ers*_* Er 1 c mmap memcpy

我需要在进程之间使用共享内存,我在这里找到了一个示例代码.首先,我需要学习如何创建共享内存块并在其中存储字符串.为此,我使用以下代码:

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <string.h>
#include <unistd.h>

void* create_shared_memory(size_t size) {
  // Our memory buffer will be readable and writable:
  int protection = PROT_READ | PROT_WRITE;

  // The buffer will be shared (meaning other processes can access it), but
  // anonymous (meaning third-party processes cannot obtain an address for it),
  // so only this process and its children will be able to use it:
  int visibility = MAP_ANONYMOUS | MAP_SHARED;

  // The remaining parameters to `mmap()` are not important for this use case,
  // but the manpage for `mmap` explains their purpose.
  return mmap(NULL, size, protection, visibility, 0, 0);
}



int main() {
  char msg[] = "hello world!";

  void* shmem = create_shared_memory(1);
  printf("sizeof shmem: %lu\n", sizeof(shmem));
  printf("sizeof msg: %lu\n", sizeof(msg));
  memcpy(shmem, msg, sizeof(msg));
  printf("message: %s\n", shmem);

}
Run Code Online (Sandbox Code Playgroud)

输出:

sizeof shmem: 8
sizeof msg: 13
message: hello world!
Run Code Online (Sandbox Code Playgroud)

在main函数中,我创建了1个字节的共享内存块(shmem)并尝试在其中存储13个字节的信息(char msg[]).当我打印出来时shmem,它会打印整条信息.我期待它,在这种情况下它只打印出1字节的消息"h".或者它可能在编译时给出有关内存大小的错误.

问题是我在这里失踪了吗?或者是否存在实施问题?不memcpy重叠在这里?我很感激任何简短的解释.

提前致谢.

Eri*_*hil 6

  1. printf("message: %s\n", shmem);,%s说明者说打印从"开始"的"字符串" shmem.为此,字符串是以空字符结尾的字符序列.因此,printf它将找到的所有字节打印shmem到空字符.要将其限制为最多一个字符,您可以%.1s改为使用,或者可以使用显式打印字符printf("message: %c\n", * (char *) shmem);.

  2. 使用时分配内存时mmap,系统以页为单位使用内存.页面大小因系统而异,但通常为512或4096字节,而不是1.标准规范mmap仅保证您提供的字节数.除此之外可能还有其他字节可访问,但您不应该依赖它们.(即使它们似乎暂时可用,当程序暂时从内存中换出时,系统可能无法将它们保存到磁盘,因此当程序返回内存以继续运行时,它们将无法恢复.)

  3. sizeof(shmem)提供shmem指针的大小.因此它提供了指针的大小,在现代系统上通常为4或8个字节.它没有提供shmem指向的东西的大小.

  4. 相反,在sizeof(msg),msg是一个数组,而不是一个指针,所以sizeof(msg)确实提供了数组的大小,因为你可能打算.

  5. memcpy(shmem, msg, sizeof(msg));复制13个字节(你的大小msg)shmem.那十三个字节是"hello world!",最后是一个空字符(值0).memcpy除了您传递的长度参数之外,没有任何方法可以知道源或目标的长度.所以它复制sizeof(msg)字节.它并不局限于指向的内存大小shmem.通过正确的长度是你的工作.

要回答有关如果使用的字节多于mmap提供的字符数会发生什么情况的问题,则行为未定义.如果超出页面边界,则程序很可能会崩溃,因为超出该地址的内存未映射.但是您可能会将字节写入内存中您不想要的位置,这可能会导致各种各样的事情发生,因为它可能会损坏程序需要正确执行的代码或数据.

在这种情况下,您没有写入映射内存.你问了13个字节,可能给了4096(或者你系统上的任何一个页面).然后你将这13个字节复制到缓冲区并打印出来.所以一切都"有效".