用于迭代像数组一样的struct成员的C方法?

假设我有一个矢量类:

typedef struct vec3_s { float x, y, z; } vec3; 

但是,我希望能够迭代它而不将其转换为浮点数组。 虽然在这种情况下演员阵容是可以接受的,但我很想知道在C ++中是否有任何类似function的东西在C语言中是可行的。例如,在C ++中,因为std::vector具有subscript []运算符重载,我可以将其第一个索引的地址传递给一个带void*的函数void*

 void do_something_with_pointer_to_mem( void* mem ) { // do stuff } int main( void ) { std::vector v; // fill v with values here // pass to do_something_with_pointer_to_mem do_some_with_pointer_to_mem( &v[ 0 ] ); return; } 

另一个更具体的例子是在OpenGL中使用glBufferData(…)时(使用C ++时):

glBufferData( GL_ARRAY_BUFFER, sizeof( somevector ), &somevector[ 0 ], GL_STREAM_DRAW );

那么,是否有可能使用下标运算符在C中完成类似的事情? 如果没有,并且我必须编写一个函数(例如, float vec3_value_at( unsigned int i ) ),那么在它定义的头文件中static inline它是否有意义?

如果所有结构字段都是相同类型,则可以使用union作为以下内容:

 typedef union vec3_u { struct vec3_s { float x, y, z; }; float vect3_a[3]; } vec3; 

这样,您可以独立访问每个x,y或z字段,或使用vect3_a数组迭代它们。 这个解决方案在内存或计算方面没有任何成本,但我们可能与C ++类似的解决方案有点远。

你没有得到C ++的语法糖,但你可以很容易地用C ++编写函数作为operator []。

 float get_vec3(v *vec3, int i) { switch(i) { case 0: return v->x; case 1: return v->y; case 2: return v->z; } assert(0); } 

现在你可以遍历任何vec3。

  for (int i = 0; i < 3; i++) { printf("%f\n", get_vec3(v, i)); } 

C中的问题与你要做的是你需要知道如何在结构中移动(即你需要知道类型)。 std::vector工作原理是因为它使用的是模板( C++概念)。 现在,说,你可以尝试一些与你建议的略有不同的东西。 如果您不想使用任何数组,则可以存储generics类型。 但是,在检索数据并使用它时,用户必须知道他或她期望的数据类型。 下面避免了数组(虽然,使用它们时可能更清晰的解决方案)并且有一个链接列表实现的东西,它给你几乎相同的std::vector灵活性(除了性能优势,因为这是一个带有O(n)的链表O(n)对所有事情的操作(你可以聪明地反转列表来实现,也许是O(1)插入,但这仅仅是例如)

 #include  #include  typedef struct _item3_t { void *x, *y, *z; struct _item3_t* next; } item3_t; typedef struct { item3_t* head; } vec3_t; void insert_vec3(vec3_t* vec, void* x, void* y, void* z) { item3_t* item = NULL; item3_t* tmp = NULL; int i = 0; if(vec == NULL) return; item = malloc(sizeof(item3_t)); item->x = x; item->y = y; item->z = z; item->next = NULL; tmp = vec->head; if(tmp == NULL) { // First element vec->head = item; } else { while(tmp->next != NULL) tmp = item->next; tmp->next = item; } } // This is one method which simply relies on the generic method above void insert_vec3_float(vec3_t* vec, float x, float y, float z) { float* xv, *yv, *zv; if(vec == NULL) return; xv = malloc(sizeof(float)); yv = malloc(sizeof(float)); zv = malloc(sizeof(float)); *xv = x; *yv = y; *zv = z; insert_vec3(vec, xv, yv, zv); } void init_vec3(vec3_t* vec) { if(vec == NULL) return; vec->head = NULL; } void destroy_vec3(vec3_t* vec) { item3_t* item = NULL, *next = NULL; if(vec == NULL) return; item = vec->head; while(item != NULL) { next = item->next; free(item->x); free(item->y); free(item->z); free(item); item = next; } } item3_t* vec3_get(vec3_t* vec, int idx) { int i = 0; item3_t* item = NULL; if(vec == NULL) return NULL; item = vec->head; for(i = 0 ; i < idx && item != NULL ; ++i) item = item->next; return item; } void do_something(item3_t* item) { if(item == NULL) return; float x = *((float*)item->x); float y = *((float*)item->y); float z = *((float*)item->z); // To do - something? Note, to manipulate the actual // values in the vector, you need to modify their values // at their mem addresses } int main() { vec3_t vector; init_vec3(&vector); insert_vec3_float(&vector, 1.2, 2.3, 3.4); printf("%f %f %f\n", *((float*)vec3_get(&vector, 0)->x), *((float*)vec3_get(&vector, 0)->y), *((float*)vec3_get(&vector, 0)->z)); do_something(vec3_get(&vector, 0)); destroy_vec3(&vector); return 0; } 

这段代码应该开箱即用。 你在这里有一个链表,它是你的“矢量”(特别是vec3结构)。 列表中的每个节点(即std::vector意义上的每个元素)都有3个元素,这些元素都是void指针。 因此,您可以存储您希望的任何数据类型。 唯一的问题是你需要为那些指向指针的指针分配内存,当你删除一个元素时,你需要释放那个内存(例如,参考vec3_destroy方法)。 希望这有助于理解这些void指针在您的情况下如何工作。

要检索数据,您将无法使用[]表示法,但您可以以相同的方式使用vec3_get方法。 do_something方法是一种示例存根,您可以通过某种方式完成类似于您在OP中提到的内容。