shmget 是如何分配内存的?无法使用线性寻址访问(地址边界错误)
How does shmget allocate memory? Cannot access with linear addressing (Address Boundary error)
在下面的示例中,我尝试使用 shmget
为 一个整数和 10 个 foo
结构 分配内存并尝试访问他们线性。但是,它会出现 "Address Boundary error".
错误
对于 MacOS 系统(但在 Linux 上应该是相同的),我尝试分配两个数据结构应该占用的确切内存量,并尝试对它们进行线性字节寻址。
#include <stdio.h>
#include <sys/shm.h>
typedef struct {
int f1;
int f2;
} foo;
int main() {
// Size of memory. Consider, int size to be 4. (4 + 8 * 10 = 84 bytes)
const int shmsz = sizeof(int) + sizeof(foo) * 10;
// Create shared mem id.
const int shmid = shmget(IPC_PRIVATE, shmsz, 0666);
if (shmid < 0) {
perror("shmget failed.");
return 1;
}
// Pointer to the shared memory. Cast as char* for byte addressing.
char* shmemPtr = (char*) shmat(shmid, 0, 0);
if (*shmemPtr == -1) {
perror("shmat failed.");
return 1;
}
// The integer should point to the first 4 bytes. This is the same as
// the address pointed to by shmemPtr itself.
int* iPtr = (int*) shmemPtr[0];
// The 80 bytes for the 10 foos range from index 4 -> 83
foo* fPtr = (foo*) ((void*) shmemPtr[sizeof(int)]);
printf("i: %p\n", iPtr); // why is this 0x0 ?
printf("x: %p\n", fPtr); // why is this 0x0 ?
*iPtr = 0; // <-- This dereference crashes, probably since the address of iPtr is 0x0
}
分配内存并通过 shmat
接收指向它的指针后,我尝试创建的指向已分配内存的任何指针都是 0x0
并且任何取消引用都会(理所当然地)使程序崩溃。我希望 int*
和 foo*
是指向共享内存的有效指针。
我只是用 C/C++ 涉猎一些系统的东西所以如果我在这里遗漏任何东西请原谅我。
char* shmemPtr = (char*) shmat(shmid, 0, 0);
你现在有一个指向共享内存块的指针。它是一个 char *
,指向块的开始。到目前为止,还不错。
int* iPtr = (int*) shmemPtr[0];
因为 shmemPtr
是一个 char *
,shmemPtr[0]
是它的第一个字节。上面莫名其妙地将一个字节转换成一个int *
。这当然没有意义。
您显然打算将 shmemPtr
重新解释为指向您的 int
的指针,因此您可以 *iPtr
以便阅读您期望的第一个 int
在您的共享内存块中。如果是这样,这应该是:
int* iPtr = (int*) shmemPtr;
那是针对 C 的。如果你使用的是 C++,你还可以帮助你的编译器帮助你避免搬起石头砸自己的脚:
int* iPtr = reinterpret_cast<int *>(shmemPtr);
锐意进取,我们来到:
foo* fPtr = (foo*) ((void*) shmemPtr[sizeof(int)]);
恭喜。 shmemPtr[sizeof(int)]
显然是 shmemPtr[4]
,或共享内存块中的第五个字节;然后你只是拖着你的编译器,又踢又叫,先把那个单字节转换成 void *
,然后再转换成 foo *
。
显然,您的意思是计算该字节的 地址,然后重新解释它。
foo* fPtr = (foo *)(shmemPtr + sizeof(int)); /* C default */
foo* fPtr = reinterpret_cast<foo *>(shmemPtr + sizeof(int)); /* Preferred in C++ */
由于特定于平台的对齐问题,这仍然可能 100% 正确,也可能不是 100% 正确。但这将是一个好的开始。
在下面的示例中,我尝试使用 shmget
为 一个整数和 10 个 foo
结构 分配内存并尝试访问他们线性。但是,它会出现 "Address Boundary error".
对于 MacOS 系统(但在 Linux 上应该是相同的),我尝试分配两个数据结构应该占用的确切内存量,并尝试对它们进行线性字节寻址。
#include <stdio.h>
#include <sys/shm.h>
typedef struct {
int f1;
int f2;
} foo;
int main() {
// Size of memory. Consider, int size to be 4. (4 + 8 * 10 = 84 bytes)
const int shmsz = sizeof(int) + sizeof(foo) * 10;
// Create shared mem id.
const int shmid = shmget(IPC_PRIVATE, shmsz, 0666);
if (shmid < 0) {
perror("shmget failed.");
return 1;
}
// Pointer to the shared memory. Cast as char* for byte addressing.
char* shmemPtr = (char*) shmat(shmid, 0, 0);
if (*shmemPtr == -1) {
perror("shmat failed.");
return 1;
}
// The integer should point to the first 4 bytes. This is the same as
// the address pointed to by shmemPtr itself.
int* iPtr = (int*) shmemPtr[0];
// The 80 bytes for the 10 foos range from index 4 -> 83
foo* fPtr = (foo*) ((void*) shmemPtr[sizeof(int)]);
printf("i: %p\n", iPtr); // why is this 0x0 ?
printf("x: %p\n", fPtr); // why is this 0x0 ?
*iPtr = 0; // <-- This dereference crashes, probably since the address of iPtr is 0x0
}
分配内存并通过 shmat
接收指向它的指针后,我尝试创建的指向已分配内存的任何指针都是 0x0
并且任何取消引用都会(理所当然地)使程序崩溃。我希望 int*
和 foo*
是指向共享内存的有效指针。
我只是用 C/C++ 涉猎一些系统的东西所以如果我在这里遗漏任何东西请原谅我。
char* shmemPtr = (char*) shmat(shmid, 0, 0);
你现在有一个指向共享内存块的指针。它是一个 char *
,指向块的开始。到目前为止,还不错。
int* iPtr = (int*) shmemPtr[0];
因为 shmemPtr
是一个 char *
,shmemPtr[0]
是它的第一个字节。上面莫名其妙地将一个字节转换成一个int *
。这当然没有意义。
您显然打算将 shmemPtr
重新解释为指向您的 int
的指针,因此您可以 *iPtr
以便阅读您期望的第一个 int
在您的共享内存块中。如果是这样,这应该是:
int* iPtr = (int*) shmemPtr;
那是针对 C 的。如果你使用的是 C++,你还可以帮助你的编译器帮助你避免搬起石头砸自己的脚:
int* iPtr = reinterpret_cast<int *>(shmemPtr);
锐意进取,我们来到:
foo* fPtr = (foo*) ((void*) shmemPtr[sizeof(int)]);
恭喜。 shmemPtr[sizeof(int)]
显然是 shmemPtr[4]
,或共享内存块中的第五个字节;然后你只是拖着你的编译器,又踢又叫,先把那个单字节转换成 void *
,然后再转换成 foo *
。
显然,您的意思是计算该字节的 地址,然后重新解释它。
foo* fPtr = (foo *)(shmemPtr + sizeof(int)); /* C default */
foo* fPtr = reinterpret_cast<foo *>(shmemPtr + sizeof(int)); /* Preferred in C++ */
由于特定于平台的对齐问题,这仍然可能 100% 正确,也可能不是 100% 正确。但这将是一个好的开始。