C/C++ malloc 一块内存,然后将不同的部分用于不同的任意类型
C/C++ malloc a block of memory and then use different portion for different, arbitrary types
我当然没有理由这样做。假设我很无聊,想探索这是否可能。 :)
假设我想实现一个链表的节点。我当然可以
struct Node {
int val;
Node *prev, *next;
}
但是假设我很无聊,我想为一个节点做一些类似 malloc-ing 内存块的事情,然后任意决定第一部分是指向前一个节点的指针,中间部分是值,最后一部分是指向下一个节点的指针。可行吗?
我试过类似的方法,但没有成功 运行。
*second = first
特别失败。
void** createNewNode(int val) {
void** p = (void**)malloc(sizeof(int) + 2*sizeof(void*));
*(p+1) = &val;
}
void connectTwoNodes(void** first, void** second) {
*(first+2) = second;
cout << "first assigned!" << endl;
*second = first;
cout << "second assigned!" << endl;
}
int main() {
void** p1 = createNewNode(1);
void** p2 = createNewNode(2);
cout << "both created!" << endl;
connectTwoNodes(p1, p2);
return 0;
}
嗯,大体思路是可以的,但是你的代码有很多错误:
p+1
和 first + 2
是非法的,因为您不能在 void *
上进行点运算。在进行算术运算之前,您必须将指针转换为指向完整的类型。
*second
是非法的,因为 void
是一个不完整的类型。
sizeof(void *)
可能与 sizeof(Node *)
不同
- 如果您曾经打算写
struct Node *ptr = p1;
,由于结构填充,那实际上是行不通的。同样,尝试通过强制转换地址来访问 Node *
指针可能会由于对齐而失败。您必须 memcpy
从存储中取出指针。
一般来说,您可以根据对齐方式和严格的别名规则将您喜欢的任何内容读写到 malloc
的 space 中。换句话说,后者说如果你将一些东西写入内存,那么你不能将它作为不同的类型读出(除非不同的类型是字符类型)。但是你可以覆盖它。
我无法弄清楚你在 connectTwoNodes
中试图做什么。但是在 C 中执行类似操作的代码可能是:
void *createNewNode(int val)
{
char *cp = malloc(sizeof(int) + 2 * sizeof(void *));
void *null_node = NULL;
memcpy(cp, &val, sizeof val);
memcpy(cp + sizeof val, &null_node, sizeof null_node);
memcpy(cp + sizeof val + sizeof null_node, &null_node, sizeof null_node);
return cp;
}
void connectTwoNodes(void* first, void* second)
{
char *c1 = first, *c2 = second;
// first->next = second
memcpy(c1 + sizeof(int) + sizeof(void*), &second, sizeof second);
// second->prev = first
memcpy(c2 + sizeof(int), &first, sizeof first);
}
int main()
{
void* p1 = createNewNode(1);
void* p2 = createNewNode(2);
connectTwoNodes(p1, p2);
}
tl;dr:不要这样做
补充一下其他人所说的,您也不能假设结构的大小与其字段大小的总和相同。
我当然没有理由这样做。假设我很无聊,想探索这是否可能。 :)
假设我想实现一个链表的节点。我当然可以
struct Node {
int val;
Node *prev, *next;
}
但是假设我很无聊,我想为一个节点做一些类似 malloc-ing 内存块的事情,然后任意决定第一部分是指向前一个节点的指针,中间部分是值,最后一部分是指向下一个节点的指针。可行吗?
我试过类似的方法,但没有成功 运行。
*second = first
特别失败。
void** createNewNode(int val) {
void** p = (void**)malloc(sizeof(int) + 2*sizeof(void*));
*(p+1) = &val;
}
void connectTwoNodes(void** first, void** second) {
*(first+2) = second;
cout << "first assigned!" << endl;
*second = first;
cout << "second assigned!" << endl;
}
int main() {
void** p1 = createNewNode(1);
void** p2 = createNewNode(2);
cout << "both created!" << endl;
connectTwoNodes(p1, p2);
return 0;
}
嗯,大体思路是可以的,但是你的代码有很多错误:
p+1
和first + 2
是非法的,因为您不能在void *
上进行点运算。在进行算术运算之前,您必须将指针转换为指向完整的类型。*second
是非法的,因为void
是一个不完整的类型。sizeof(void *)
可能与sizeof(Node *)
不同
- 如果您曾经打算写
struct Node *ptr = p1;
,由于结构填充,那实际上是行不通的。同样,尝试通过强制转换地址来访问Node *
指针可能会由于对齐而失败。您必须memcpy
从存储中取出指针。
一般来说,您可以根据对齐方式和严格的别名规则将您喜欢的任何内容读写到 malloc
的 space 中。换句话说,后者说如果你将一些东西写入内存,那么你不能将它作为不同的类型读出(除非不同的类型是字符类型)。但是你可以覆盖它。
我无法弄清楚你在 connectTwoNodes
中试图做什么。但是在 C 中执行类似操作的代码可能是:
void *createNewNode(int val)
{
char *cp = malloc(sizeof(int) + 2 * sizeof(void *));
void *null_node = NULL;
memcpy(cp, &val, sizeof val);
memcpy(cp + sizeof val, &null_node, sizeof null_node);
memcpy(cp + sizeof val + sizeof null_node, &null_node, sizeof null_node);
return cp;
}
void connectTwoNodes(void* first, void* second)
{
char *c1 = first, *c2 = second;
// first->next = second
memcpy(c1 + sizeof(int) + sizeof(void*), &second, sizeof second);
// second->prev = first
memcpy(c2 + sizeof(int), &first, sizeof first);
}
int main()
{
void* p1 = createNewNode(1);
void* p2 = createNewNode(2);
connectTwoNodes(p1, p2);
}
tl;dr:不要这样做
补充一下其他人所说的,您也不能假设结构的大小与其字段大小的总和相同。