我发现Converting double to void* in C但我不能让没有任何解决方案的运行。我想创建一个结构与一个空指针来存储不同类型的数据。
struct Table {
int id;
void *val;
};
在主函数我分配等的值
struct Table t;
int i = 1;
double d = 2.5;
double *pd = &d;
void **p = (void**)pd;
void *dp = *p;
t.id = i;
t.val = dp;
但我不能得到双重的价值..
printf("%d %f", t.id, t.val);
谢谢。
几点:
pd
分配d
的地址t.val
。以下应完全正常工作:
t.val = &d;
C允许void *
和其他指针类型之间的直接分配。 C ++没有,所以在C时不强制转换,这将不起作用++:
t.val = (void *) &d;
t.val
的生命周期中使用d
。如果有机会,d
会走出去的范围使用t.val
之前,那么你应该分配的内存块的新存储d
的价值:
t.val = malloc( sizeof d );
if ( t.val )
*(double *)t.val = d;
因此,而不是存储d
的地址t.val
,你存储的内存动态分配块的地址,并d
的值复制到动态块。由于t.val
是一个指向void
,首先需要使用转换表达式(double *)
告诉编译器把它当作一个指针double
。然后,你需要提领与一元*
操作该指针d
的值分配给新的内存块。这也意味着你将需要解除对其块当你用它做:
free( t.val );
t.val
点值,如下所示:
printf( "%d %f\n", t.id, *(double *)t.val );
同样,我们必须告诉编译器把t.val
为指针,以double
并使用一元*
运营商获得的价值指针指向。编辑
下面是我的意思大约d
“走出去的范围”非常牵强的例子。让我们假设,我们建立t
的main
对象,然后调用一个函数,该函数使用一个局部变量分配t.val
,然后调用另一个函数以打印t.val
点的值:
/**
* Sets the val member of a struct Table object. Since we want to
* modify the contents of the parameter, we need to pass a pointer
* to it.
*/
void assignVal( struct Table *tbl )
{
double d = some_value(); // d only exists for the duration of this function
...
tbl->val = malloc( sizeof d ); // since tbl is a pointer, use ->
if ( tbl->val ) // instead of . to access members
*(double *) tbl->val = d;
else
// error could not allocate memory for tbl->val
...
}
void printVal( struct Table tbl )
{
...
if ( tbl.val )
printf( "%d %f\n", tbl->id, *(double *) tbl.val );
else
// tbl.val was never allocated
...
}
int main( void )
{
struct Table t;
assignVal( &t );
printVal( t );
if ( t.val )
free( t.val );
}
既然我们要assignVal
修改t
的内容,我们需要一个指针传递给它作为参数。语法tbl->val
相同(*tbl).val
- 我们解引用尝试访问tbl
成员之前val
。
由于d
停止尽快assignVal
退出存在,我们需要分配一个新的对象来存储d
的价值。一旦我们该值完成后,我们免费t.val
。
在这个例子中,assignVal
和printVal
都假定t.val
指向double
对象。欲了解更多通用的代码,您可能要添加跟踪的对象val
指向型的另一个成员。
例如:
struct Table {
int id;
int valueType;
void *val;
};
void assignDblVal( struct Table *tbl )
{
double d = ...;
...
t->valueType = DOUBLE; // where DOUBLE is some kind of integer constant
t->val = malloc( sizeof d );
if ( t->val )
*(double *) t->val = d;
...
}
void assignIntVal( struct Table *tbl )
{
int x = ...;
...
tbl->valueType = INT;
tbl->val = malloc( sizeof x );
if ( tbl->val )
*(int *) tbl->val = x;
...
}
void printVal( struct Table tbl )
{
switch( tbl.valueType )
{
case CHAR:
printf( "%d '%c'\n", tbl.id, *(char *) tbl.val );
break;
case INT:
printf( "%d %d\n", tbl.id, *(int *) tbl.val );
break;
...
case DOUBLE:
printf( "%d %f\n", tbl.id, *(double *) tbl.val );
break;
...
}
}
这样一来,printVal
不必假设tbl.val
指向双 - 我们告诉它指向的是什么类型,并使用合适的演员和格式说明做印刷。
请记住,这些都是快速正肮脏的例子。还有我现在不能想到一个处理在C型的多态性的要聪明的方式。
要打印值试试
printf("%d %f", t.id, *(double*)t.val);
t.val
是一个指针,而不是价值本身,而是因为它是一个void*
你不能取消对它的引用不进行强制转换为正确的类型,这是你的简单的例子(double*)
。
要存储数据,你并不需要的三分。你可以简单地分配地址:
t.id = i;
t.val = &d;
有这种方法有两个可能的问题。
struct Table
当你想使用(打印)的价值,因为你必须使用corrent演员。 (也许你需要一个额外的type
场在你的结构。)double d = 2.5;
)使用带有自动或静态存储变量及其地址存储在t.val
你必须确保该变量没有得到无效的,你不要在以后修改它的值。 (也许你需要动态分配内存以创建变量的副本。)双重的大小是64位,而一个空指针是在32位的程序32个比特,并在一个64位程序64位。
所以,你可以做,在一个64位可执行文件,但不能在32位之一。
如果你想不同类型的数据存储在那样的结构,你可以使用包含每个数据类型的联合。见https://www.tutorialspoint.com/cprogramming/c_unions.htm。