所以,我是一个尝试学习C的C#人。作为第一个(个人)项目,我试图编写一个基本的坐标几何库。
问题:再次最好的C编程实践是在幕后的堆上分配内存而不是让那些以图书馆为目标的程序员做这件事吗?
例如,我的'点'结构&相关方法:
point.h
/* A basic point type. */
typedef struct point
{
float x;
float y;
float z;
char *note;
}point;
/* Initializes a basic point type. [Free with free_point method] */
point *create_point(float pos_x, float pos_y, float pos_z, char *_note);
/* Frees a point type. */
void free_point(point *_point);
/* Finds the midpoint between two points. */
point *midpoint(point *pt1, point *pt2);
point.c
#include "point.h"
/* Initializes a basic point type. [Free with free_point method] */
point *create_point(float pos_x, float pos_y, float pos_z, char *_note)
{
point *p;
size_t notelen = strlen(_note);
p = (point*)malloc(sizeof(point));
p->x = pos_x;
p->y = pos_y;
p->z = pos_z;
p->note = (char*)calloc(notelen + 1, sizeof(char));
strcpy_s(p->note, notelen + 1, _note);
return p;
}
/* Frees a point type. */
void free_point(point *_point)
{
free (_point->note);
free (_point);
}
/* Creates a midpoint between two points. */
point *midpoint(point *pt1, point *pt2)
{
float mid_x = (pt1->x + pt2->x) * 0.5f;
float mid_y = (pt1->y + pt2->y) * 0.5f;
float mid_z = (pt1->z + pt2->z) * 0.5f;
point *p = create_point(mid_x, mid_y, mid_z, "Midpoint");
return p;
}
请注意,我在堆上创建了结构'point',无论是谁实现/使用我的lib(通过create_point()方法,这个项目只适合我和学习,但是......)。这种做法很糟糕吗?感觉就像我强迫用户以某种方式编程。中点()方法也是如此。同样,您必须使用指向'point'结构的指针。
我无法在SO上找到有关C库设计的确切问题,但如果适用,请指出正确的方向。
感谢。
答案 0 :(得分:6)
这是首选,真的。我通常订阅让用户为他们希望的对象分配内存,然后为他们初始化成员。
/* here a non-zero return value might indicate if for example
* we failed to allocate memory for note */
int point_init(struct point* p, int x, int y, char* note)
{
/* ... */
}
/* usage: */
struct point p;
if (point_init(&p, 1, 2, "hello")) {
/* error */
}
这使用户可以选择分配内存中相邻的点数组,而不是跟踪指向点的指针数组:
struct point mypoints[NUM_POINTS];
for(size_t i = 0; i < NUM_POINTS; ++i) {
point_init(&mypoints[i], ...);
}
如果要使用Opaque Pointer策略从库用户隐藏结构成员,则需要使用所描述的方法为它们分配内存。这对于在库中分配结构肯定是一个巨大的好处。
答案 1 :(得分:3)
最佳做法是以这样的方式对库进行编码,使程序员可以执行最快的,因为这是C的强项。例如,程序员可能知道数十将需要数千个这样的点结构,并且为了保持将来的访问,本地可能更喜欢在一个存储器块中分配所有结构。如果你的库让程序员通过指针来初始化结构,那么他就可以做到这一点。但如果你坚持为他分配记忆,他就不能。