我需要在进程之间使用共享内存,我发现了一个示例代码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个字节复制到缓冲区并打印出来。所以一切都“奏效”