【问题标题】:Generic data type in C [ void * ] [duplicate]C [ void * ] [重复]中的通用数据类型
【发布时间】:2011-04-05 11:58:31
【问题描述】:

您好,我正在尝试使用 void * 作为 C 中的通用数据类型。我想要的是一种机制,我可以使用它来存储和获取任何东西。我写了一些代码,但在最后一种情况下它失败了。任何人都可以看看代码,如果您有任何其他想法,请告诉我。

我知道我要存储什么,所以那时我知道数据类型,但在重试期间我只知道起始地址和大小。

代码如下:

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

} 

【问题讨论】:

    标签: c


    【解决方案1】:

    最好使用您需要的所有类型的联合,而不是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 保护,因此您需要确保在使用此结构的任何地方都正确设置了枚举。

    【讨论】:

    • @Benoit Thiery,你能否解释更多,如果你有任何例子。我对结构解决方案很感兴趣。
    • 感谢 Benoit,但我的类型列表是有限的,所以请您进一步了解 struct 方法。
    • @Avinash,即使你有一个有限的类型列表,联合仍然更好。联合几乎与结构相同。
    • 但在这种情况下如何处理结构指针?
    • 我正在尝试用 C 语言编写一个 stl 向量,如果客户端在堆上分配内存并作为元素传递给我,我可以这样做。但我希望它与基本数据类型一起工作,不应该有特殊的方式来传递堆栈或堆变量上的变量,有办法使用 MACROS 来做到这一点,但我正在寻找避免 MACROS 的选项。
    【解决方案2】:

    您将整数值 (55) 复制到指针 int_out 中。无论位于地址 55(接下来的 4 到 8 个字节)处的什么,都不太可能具有数值 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 部分中,您只需要复制指针值。这有效(在这种情况下),但不太可能是您真正想要的,或者是吗?如果你真的想存储指针,你可以跳过storeretrieve部分:

    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),并将指针保存到 copy字符串:

    char* str_in = _strdup("copy me");
    void* generic_ptr = str_in;         // Gets stored in your data structures
    

    【讨论】:

      【解决方案3】:

      您正在覆盖指针,然后取消引用它...如果您的代码看起来像这样,它会起作用...但这可能不是您想要的。

          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*' 的大小相同,因此您可以在检索时将一个存储在另一个之上。我相信并非所有系统都如此。

      【讨论】:

        【解决方案4】:

        德克是完全正确的。 另一种表达方式是,没有分配空间来放入检索到的数据。

        尝试:

        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() 是否失败,但这应该会让您走上正轨。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-03-30
          • 2013-04-26
          • 2019-05-26
          • 2012-02-09
          • 2018-05-26
          • 2012-08-21
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多