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

#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);

}

输出:
sizeof shmem: 8
sizeof msg: 13
message: hello world!

在main函数中,我正在创建1字节的共享内存块(shmem),并尝试在其中存储13字节的信息(char msg[])。当我打印出shmem时,它会打印整个消息。我希望,它只打印出1字节的消息,在本例中就是"h"。或者在编译时会给出内存大小的错误。
问题是我在这里遗漏了什么?还是有执行问题?这里有重叠吗?我很感激你的简短解释。
提前谢谢。

最佳答案

printf("message: %s\n", shmem);中,%s说明符表示从shmem开始打印“字符串”。为此,字符串是以空字符结尾的字符序列。所以printf会将它在shmem处找到的所有字节打印到空字符。若要将其限制为最多一个字符,可以改用%.1s,也可以使用printf("message: %c\n", * (char *) shmem);显式打印字符。
使用mmap分配内存时,系统将使用以页为单位的内存。页面大小因系统而异,但通常是512或4096字节,而不是1。mmap的标准规范仅保证提供您请求的字节数。除此之外,还可以访问其他字节,但不应依赖这些字节的可用性。(即使它们看起来是暂时可用的,当您的程序被临时调出内存时,系统可能不会将它们保存到磁盘上,因此当您的程序被调回内存以继续运行时,它们不会被还原。)
sizeof(shmem)提供shmem的大小,它是一个指针。所以它提供了指针的大小,在现代系统上通常是4或8个字节。它不提供shmem指向的对象的大小。
相反,在sizeof(msg)中,msg是一个数组,而不是指针,因此sizeof(msg)确实提供了数组的大小,正如您所希望的那样。
memcpy(shmem, msg, sizeof(msg));将13个字节(您的msg大小)复制到shmem中。那十三个字节是“你好,世界!”和结尾的空字符(值0)。memcpy无法知道源或目标的长度,但传递的长度参数除外。所以它复制sizeof(msg)字节。它不会将自身限制为shmem指向的内存大小。通过正确的长度是你的工作。
要回答如果使用的字节数超过mmap提供的字节数会发生什么的问题,行为是未定义的。如果超出页面边界,程序很可能会崩溃,因为超出该地址的内存没有映射。但是,您可能会将字节写入内存中不希望写入的位置,这可能会导致各种情况的发生,因为这可能会损坏程序正常执行所需的代码或数据。
在本例中,您没有写超出映射内存的内容。你要求13个字节,很可能得到4096个字节(或者系统上的任何一个页面)。然后将这13个字节复制到缓冲区并打印出来。所以一切都“奏效”

09-27 08:08