使用(void *)作为通用数据容器时的L值问题

这是程序中使用的结构:

struct basic_block { void * aux; /* Many other fields, which are irrelevant. */ }; 

现在:

  1. 在程序执行期间存在几个basic_block实例。
  2. 该程序分阶段/通过,一个接一个地执行。
  3. aux字段用于在阶段执行期间存储stage和basic_block特定数据,并由阶段本身释放(因此下一阶段可以重用它)。 这就是为什么它是一个void *

我的舞台使用aux来存储一个struct ,所以每次我想访问某些东西时,我都要做一个强制转换:

 ( (struct a_long_struct_name *) (bb->aux))->foo_field = foo; 

现在,我的问题:每次像这样投下它是一种痛苦,当它是更复杂的表达式的一部分时难以阅读。 我建议的解决方案是:使用宏为我做演员:

 #define MY_DATA(bb) \ ( (struct a_long_struct_name *) (bb)->aux) 

然后我可以访问我的数据:

 MY_DATA(bb)->foo_field = foo; 

但是:我不能将MY_DATA(bb) 本身用作L值(对于malloc ),所以我使用该宏并不是一个好主意:

 /* WRONG! I cannot assign to the result of a cast: */ MY_DATA(bb) = malloc (sizeof (struct a_long_struct_name)); 

我的问题:

我该怎么做才能以干净的方式引用aux并仍能将其用作L值。

您可以将字段的地址 struct a_long_struct_name **struct a_long_struct_name ** ,然后取消引用它:

 #define MY_DATA(bb) \ (* ((struct a_long_struct_name **) &(bb)->aux) ) 

这将适用于您显示的两种结构。

但是,如果可以在声明struct basic_block的位置知道具体类型的aux的可能性,那么使用union会更清晰:

 struct basic_block { union { struct a_long_struct_name *alsn; /* etc */ } aux; /* Many other fields, which are irrelevant. */ }; 

然后

 #define MY_DATA(bb) ((bb)->aux.alsn) 

尝试:

 #define MY_DATA(bb) \ ( *(struct a_long_struct_name **) &(bb)->aux) 

请注意,这会引入别名,因此您必须在使用宏时保持一致。

没有必要使用宏调用来丢弃代码:

 struct a_long_struct_name* strp = malloc(sizeof *strp); if (!strp)  bb->aux = strp; strp->foo_field = foo; etc. 

你不能。 C禁止通过不同类型的左值表达式( struct a_long_struct_name * )访问一种类型的对象( void * struct a_long_struct_name * ),并且违反此规则是一种别名冲突。 从实际角度来看,这意味着允许编译器假设这两个左值不能引用相同的内存,因此可能会以严重破坏代码的方式重新排序读取和写入。 在forms上,它只是未定义的行为,这意味着任何事情都可能发生。

你应该做的是在问题中使用你的代码的原始版本,而忘记使用MY_DATA(bb)作为左值。 而只是直接分配给bb->aux 。 这就是void *的用途。