如何存储双在用C一个void *

问题描述 投票:-2回答:3

我发现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);

谢谢。

c pointers void
3个回答
2
投票

几点:

  1. 你不需要中介pd分配d的地址t.val。以下应完全正常工作: t.val = &d; C允许void *和其他指针类型之间的直接分配。 C ++没有,所以在C时不强制转换,这将不起作用++: t.val = (void *) &d;
  2. 然而,这种假设您将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 );
  3. 无论哪种方式,您打印t.val点值,如下所示: printf( "%d %f\n", t.id, *(double *)t.val ); 同样,我们必须告诉编译器把t.val为指针,以double并使用一元*运营商获得的价值指针指向。

编辑

下面是我的意思大约d“走出去的范围”非常牵强的例子。让我们假设,我们建立tmain对象,然后调用一个函数,该函数使用一个局部变量分配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

在这个例子中,assignValprintVal都假定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型的多态性的要聪明的方式。


1
投票

要打印值试试

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你必须确保该变量没有得到无效的,你不要在以后修改它的值。 (也许你需要动态分配内存以创建变量的副本。)

0
投票

双重的大小是64位,而一个空指针是在32位的程序32个比特,并在一个64位程序64位。

所以,你可以做,在一个64位可执行文件,但不能在32位之一。

如果你想不同类型的数据存储在那样的结构,你可以使用包含每个数据类型的联合。见https://www.tutorialspoint.com/cprogramming/c_unions.htm

© www.soinside.com 2019 - 2024. All rights reserved.