您好我试图在C中使用void *作为通用数据类型。我想要的是一种机制,使用它我可以存储任何东西并得到任何东西。我写了一些代码,但在最后一种情况下失败了。任何人都可以看看代码,如果您有任何其他想法,请告诉我。
我知道我要存储的内容,所以此时我知道数据类型,但在重审期间我只知道起始地址和大小。
以下是代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
static void store( void *destination, void *source, size_t size ) {
memcpy ( (char*)destination, source, size);
}
static void retrieve ( void *destination, void *source, size_t size) {
memcpy ( destination, (char*)source, size);
}
void *storage_char_ptr = (void*) malloc ( sizeof( char* ));
void *storage_int_ptr = (void*) malloc ( sizeof(int*));
void *storage_int = (void*) malloc ( sizeof( int));
int main() {
int int_in = 65;
void *int_out_ptr;
int *ptr = ( int*) malloc ( sizeof(int));
memcpy ( ptr, &int_in, sizeof(int));
store ( storage_int_ptr, &ptr, sizeof(int*));
retrieve ( &int_out_ptr, storage_int_ptr, sizeof(int*));
assert ( int_in == *(int*)int_out_ptr);
char *char_in = "HelloWorld!!";
void *char_out;
store ( storage_char_ptr, &char_in, sizeof(char*));
retrieve ( &char_out, storage_char_ptr, sizeof(char*));
assert ( strcmp ( char_in, (char*)char_out ) == 0 );
char_in = _strdup("HelloWorld!!");
store ( storage_char_ptr, &char_in, sizeof(char*));
retrieve ( &char_out, storage_char_ptr, sizeof(char*));
assert ( strcmp ( char_in, (char*)char_out ) == 0 );
/* This is where it is failing */
int_in = 55;
void* int_out;
store ( storage_int, &int_in, sizeof(int));
retrieve ( &int_out, storage_int, sizeof(int));
assert ( 55 == *(int*)int_out);
}
答案 0 :(得分:10)
最好使用所需类型的联合而不是void*
,并结合所选类型的枚举。
如果您没有有限的类型列表,那么请使用包含void*
指针的结构,并至少分配大小。
例如:
struct ANYTYPE
{
enum {
typUndefined,
typInt, // 1
typUint,
typString,
typByteString,
typLong, // 5
typFloat,
typDouble,
} iType;
void* value;
};
这使您可以轻松地正确释放内存并生成可以在对值进行操作之前分析类型的通用代码。 你对union有类似的选择:
struct ANYTYPE
{
enum {
typUndefined,
typInt, // 1
typUint,
typString,
typLong
} iType;
union
{
int i;
unsigned int u;
char* s;
long l;
} value;
}
在联合中,所有元素都使用相同的内存空间,只能访问一个。通过枚举,您知道应该访问哪个元素。当然,你没有像C ++那样的OO保护,所以你需要确保在使用这个结构的任何地方正确设置枚举。
答案 1 :(得分:5)
您正在将整数值(55)复制到指针int_out
中。无论地址(下一个4到8个字节)地址55,它不可能有数值55.相反,尝试
int int_in = 55;
int int_out;
store ( storage_int, &int_in, sizeof(int));
retrieve ( &int_out, storage_int, sizeof(int));
assert ( 55 == int_out);
您的代码的另一个问题:在char_in
/ char_out
部分中,您只会复制指针值。这有效(在这种情况下),但不太可能是你真正想要的,或者是它?如果您确实想存储指针,可以跳过store
和retrieve
部分:
char* str_in = "hello, world"; // Original value
void* generic_ptr = str_in; // ... a pointer to which is stored in some data structure
char* str_out = generic_ptr; // ... which can later be retrieved
也会奏效。另一方面:如果您打算存储字符串的实际内容,则必须将其复制(如第二个示例中的_strdup
),并将指针保存到副本 of string:
char* str_in = _strdup("copy me");
void* generic_ptr = str_in; // Gets stored in your data structures
答案 2 :(得分:4)
你正在覆盖指针,然后取消引用它...如果你的代码看起来像这样就可以了......但这可能不是你想要的。
int int_out;
store ( storage_int, &int_in, sizeof(int));
retrive ( &int_out, storage_int, sizeof(int));
assert ( 55 == int_out);
或:
int *int_out;
store ( storage_int, &int_in, sizeof(int));
retrive ( &int_out, storage_int, sizeof(int));
assert ( 55 == (int)int_out);
然而,在第二种情况下,这有点可疑,因为它假设'int'和'int *'都是相同的大小,所以你可以在检索时将一个存储在另一个之上。我相信并非所有系统都是如此。
答案 3 :(得分:1)
德克是完全正确的。 另一种表达方式是,没有分配空间来放置检索到的数据。
尝试:
int_in = 55;
void* int_out = malloc (sizeof (int_in));
store ( storage_int, &int_in, sizeof(int));
retrieve ( int_out, storage_int, sizeof(int));
assert ( 55 == *(int*)int_out);
当然,你可能想要使用malloc()以外的东西,并且没有检查malloc()是否失败,但这应该让你走上正确的轨道。