如何在 C 中的 void * 中存储 double
How to store a double in a void * in C
我找到了 Converting double to void* in C,但我无法得到 none 运行 的解决方案。我想创建一个带有 void 指针的结构来存储不同类型的数据。
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);
谢谢。
double 的大小是 64 位,而 void 指针在 32 位程序中是 32 位,在 64 位程序中是 64 位。
因此您可以在 64 位可执行文件中执行此操作,但不能在 32 位可执行文件中执行此操作。
如果您想在这样的结构中存储不同类型的数据,您可以使用包含每种数据类型的联合。参见 https://www.tutorialspoint.com/cprogramming/c_unions.htm。
尝试打印值
printf("%d %f", t.id, *(double*)t.val);
t.val
是一个指针,而不是值本身,但因为它是一个 void*
,所以如果不强制转换为正确的类型,您就无法取消引用它,即 (double*)
在您的简单的例子。
要存储数据,您不需要三个指针。您可以简单地分配地址:
t.id = i;
t.val = &d;
这种方法可能存在两个问题。
如果你想要 "to store different types of data" 你必须知道你的 struct Table
中存储的是什么类型当你想使用(打印)值时,因为你必须使用当前演员表。 (也许您的结构中需要一个额外的 type
字段。)
如果您使用具有自动或静态存储的变量(如示例中的 double d = 2.5;
)并将其地址存储在 t.val
中,您必须确保该变量不会不会变得无效并且您以后不会修改它的值。 (也许您需要动态内存分配来创建变量的副本。)
几点:
- 您不需要中介
pd
将d
的地址分配给t.val
。以下应该工作得很好:
t.val = &d;
C 允许在 void *
和其他指针类型之间直接赋值。 C++ 没有,所以如果没有强制转换,这在 C++ 中是行不通的:
t.val = (void *) &d;
- 但是,这假设您将在
d
的生命周期内使用 t.val
。如果在使用 t.val
之前 d
有可能超出范围,那么您应该分配一个新的内存块来存储 d
的值:
t.val = malloc( sizeof d );
if ( t.val )
*(double *)t.val = d;
因此,不是将 d
的地址存储在 t.val
中,而是存储动态分配的内存块的地址,并将 d
的值复制到该动态块。由于 t.val
是指向 void
的指针,因此您首先需要使用强制转换表达式 (double *)
告诉编译器将其视为指向 double
的指针。然后,您需要使用一元 *
运算符取消引用该指针,以将 d
的值分配给该新内存块。这也意味着您需要在完成后 de 分配该块:
free( t.val );
- 无论哪种方式,您都打印
t.val
指向的值,如下所示:
printf( "%d %f\n", t.id, *(double *)t.val );
同样,我们必须告诉编译器将 t.val
视为指向 double
的指针,并使用一元运算符 *
来获取指针指向的值。
编辑
这是我所说的 d
"going out of scope" 的一个非常人为的例子。假设我们在 main
中创建了 t
对象,然后调用一个使用该函数中的局部变量赋值 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
相同 - 我们在尝试访问 val
成员之前取消引用 tbl
。
由于assignVal
一退出,d
就不存在了,我们需要分配一个新的对象来存储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 中有很多更聪明的方法来处理类型多态性。我现在想不出一个。
我找到了 Converting double to void* in C,但我无法得到 none 运行 的解决方案。我想创建一个带有 void 指针的结构来存储不同类型的数据。
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);
谢谢。
double 的大小是 64 位,而 void 指针在 32 位程序中是 32 位,在 64 位程序中是 64 位。
因此您可以在 64 位可执行文件中执行此操作,但不能在 32 位可执行文件中执行此操作。
如果您想在这样的结构中存储不同类型的数据,您可以使用包含每种数据类型的联合。参见 https://www.tutorialspoint.com/cprogramming/c_unions.htm。
尝试打印值
printf("%d %f", t.id, *(double*)t.val);
t.val
是一个指针,而不是值本身,但因为它是一个 void*
,所以如果不强制转换为正确的类型,您就无法取消引用它,即 (double*)
在您的简单的例子。
要存储数据,您不需要三个指针。您可以简单地分配地址:
t.id = i;
t.val = &d;
这种方法可能存在两个问题。
如果你想要 "to store different types of data" 你必须知道你的
struct Table
中存储的是什么类型当你想使用(打印)值时,因为你必须使用当前演员表。 (也许您的结构中需要一个额外的type
字段。)如果您使用具有自动或静态存储的变量(如示例中的
double d = 2.5;
)并将其地址存储在t.val
中,您必须确保该变量不会不会变得无效并且您以后不会修改它的值。 (也许您需要动态内存分配来创建变量的副本。)
几点:
- 您不需要中介
pd
将d
的地址分配给t.val
。以下应该工作得很好:
C 允许在t.val = &d;
void *
和其他指针类型之间直接赋值。 C++ 没有,所以如果没有强制转换,这在 C++ 中是行不通的:t.val = (void *) &d;
- 但是,这假设您将在
d
的生命周期内使用t.val
。如果在使用t.val
之前d
有可能超出范围,那么您应该分配一个新的内存块来存储d
的值:
因此,不是将t.val = malloc( sizeof d ); if ( t.val ) *(double *)t.val = d;
d
的地址存储在t.val
中,而是存储动态分配的内存块的地址,并将d
的值复制到该动态块。由于t.val
是指向void
的指针,因此您首先需要使用强制转换表达式(double *)
告诉编译器将其视为指向double
的指针。然后,您需要使用一元*
运算符取消引用该指针,以将d
的值分配给该新内存块。这也意味着您需要在完成后 de 分配该块:free( t.val );
- 无论哪种方式,您都打印
t.val
指向的值,如下所示:
同样,我们必须告诉编译器将printf( "%d %f\n", t.id, *(double *)t.val );
t.val
视为指向double
的指针,并使用一元运算符*
来获取指针指向的值。
编辑
这是我所说的 d
"going out of scope" 的一个非常人为的例子。假设我们在 main
中创建了 t
对象,然后调用一个使用该函数中的局部变量赋值 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
相同 - 我们在尝试访问 val
成员之前取消引用 tbl
。
由于assignVal
一退出,d
就不存在了,我们需要分配一个新的对象来存储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 中有很多更聪明的方法来处理类型多态性。我现在想不出一个。