C 通过已知的 sizeof 迭代数组
C iterate array by known sizeof
我正在尝试制作一个用于粒子管理的小型库,允许使用用户数据(纹理、动画帧等)“扩展”结构。该库将只知道扩展结构的大小。
如何遍历未知结构类型但已知结构大小的数组?
typedef struct{
int type;
}Base;
typedef struct{
Base base;
int value;
}inherited;
int main(){
size_t size = sizeof(inherited);
int count = 10;
void *b = malloc(size * count);
for (int i = 0; i < count; i++){
// iterate based on known size & send to callback
callback( &( (size)b )[i] );
}
free(b);
return 0;
}
for( inherited *p = b, *e = p + count; p < e; p++ ){
callback(p);
}
我假设执行 malloc
和调用 callback
的代码不知道对象的类型,只知道它的大小。
#include <stdlib.h>
void *alloc_and_init(size_t nmemb, size_t size, void (*callback)(void *))
{
void *b = calloc(nmemb, size);
if (b)
{
char *p = b;
for (size_t i = 0; i < nmemb; i++)
{
callback(p);
p += size;
}
}
return b;
}
typedef struct{
int type;
}Base;
typedef struct{
Base base;
int value;
}inherited;
void init_inherited(void *p)
{
inherited *obj = p;
/* do initialization of obj->* here */
}
int main(void)
{
int objcount = 10;
inherited *objarr;
objarr = alloc_and_init(objcount, sizeof(*objarr),
init_inherited);
/* ... */
free(objarr);
}
C 中的多态性总是相当笨拙。基本上你必须手动构建一个“vtable”。下面的朴素、简化版本让每个对象都有自己的函数指针。你最终会得到像这样做作的东西:
#include <stdio.h>
#include <stdlib.h>
typedef struct base_t base_t;
typedef void callback_t (const base_t* arg);
struct base_t
{
int type;
callback_t* callback;
};
typedef struct
{
base_t base;
int value;
} inherited_t;
void callback_base (const base_t* arg)
{
puts(__func__);
}
void callback_inherited (const base_t* arg)
{
const inherited_t* iarg = (const inherited_t*)arg;
printf("%s value: %d\n", __func__, iarg->value);
}
int main (void)
{
// allocate memory
base_t* array [3] =
{
[0] = malloc(sizeof(inherited_t)),
[1] = malloc(sizeof(base_t)),
[2] = malloc(sizeof(inherited_t)),
};
// initialize objects
*(inherited_t*)array[0] = (inherited_t){ .base.callback=callback_inherited, .value = 123 };
*(array[1]) = (base_t){ .callback=callback_base };
*(inherited_t*)array[2] = (inherited_t){ .base.callback=callback_inherited, .value = 456 };
for (int i = 0; i < 3; i++)
{
array[i]->callback(array[i]); // now we get polymorphism here
}
}
更专业的版本涉及为每个“class”编写一个翻译单元(.h + .c),然后在“构造函数”中将分配与初始化结合起来。它将使用不透明类型实现,参见 How to do private encapsulation in C? 在构造函数中,设置与分配的对象类型对应的 vtable。
我还大胆声称任何使用 void*
参数的 OO 解决方案都存在一些设计缺陷。该接口应该使用基 class 指针。空指针很危险。
char *b = malloc(size * count);
for (int i = 0; i < count; i++){
// iterate based on known size & send to callback
callback( b + i * size );
}
我正在尝试制作一个用于粒子管理的小型库,允许使用用户数据(纹理、动画帧等)“扩展”结构。该库将只知道扩展结构的大小。 如何遍历未知结构类型但已知结构大小的数组?
typedef struct{
int type;
}Base;
typedef struct{
Base base;
int value;
}inherited;
int main(){
size_t size = sizeof(inherited);
int count = 10;
void *b = malloc(size * count);
for (int i = 0; i < count; i++){
// iterate based on known size & send to callback
callback( &( (size)b )[i] );
}
free(b);
return 0;
}
for( inherited *p = b, *e = p + count; p < e; p++ ){
callback(p);
}
我假设执行 malloc
和调用 callback
的代码不知道对象的类型,只知道它的大小。
#include <stdlib.h>
void *alloc_and_init(size_t nmemb, size_t size, void (*callback)(void *))
{
void *b = calloc(nmemb, size);
if (b)
{
char *p = b;
for (size_t i = 0; i < nmemb; i++)
{
callback(p);
p += size;
}
}
return b;
}
typedef struct{
int type;
}Base;
typedef struct{
Base base;
int value;
}inherited;
void init_inherited(void *p)
{
inherited *obj = p;
/* do initialization of obj->* here */
}
int main(void)
{
int objcount = 10;
inherited *objarr;
objarr = alloc_and_init(objcount, sizeof(*objarr),
init_inherited);
/* ... */
free(objarr);
}
C 中的多态性总是相当笨拙。基本上你必须手动构建一个“vtable”。下面的朴素、简化版本让每个对象都有自己的函数指针。你最终会得到像这样做作的东西:
#include <stdio.h>
#include <stdlib.h>
typedef struct base_t base_t;
typedef void callback_t (const base_t* arg);
struct base_t
{
int type;
callback_t* callback;
};
typedef struct
{
base_t base;
int value;
} inherited_t;
void callback_base (const base_t* arg)
{
puts(__func__);
}
void callback_inherited (const base_t* arg)
{
const inherited_t* iarg = (const inherited_t*)arg;
printf("%s value: %d\n", __func__, iarg->value);
}
int main (void)
{
// allocate memory
base_t* array [3] =
{
[0] = malloc(sizeof(inherited_t)),
[1] = malloc(sizeof(base_t)),
[2] = malloc(sizeof(inherited_t)),
};
// initialize objects
*(inherited_t*)array[0] = (inherited_t){ .base.callback=callback_inherited, .value = 123 };
*(array[1]) = (base_t){ .callback=callback_base };
*(inherited_t*)array[2] = (inherited_t){ .base.callback=callback_inherited, .value = 456 };
for (int i = 0; i < 3; i++)
{
array[i]->callback(array[i]); // now we get polymorphism here
}
}
更专业的版本涉及为每个“class”编写一个翻译单元(.h + .c),然后在“构造函数”中将分配与初始化结合起来。它将使用不透明类型实现,参见 How to do private encapsulation in C? 在构造函数中,设置与分配的对象类型对应的 vtable。
我还大胆声称任何使用 void*
参数的 OO 解决方案都存在一些设计缺陷。该接口应该使用基 class 指针。空指针很危险。
char *b = malloc(size * count);
for (int i = 0; i < count; i++){
// iterate based on known size & send to callback
callback( b + i * size );
}