c - 在 C 中的 vector 函数序列中避免(初学者)分配错误

标签 c function pointers memory-management struct

上下文:为了提高速度,我决定将用 Python 开发的 3D 图形脚本改写为 C 语言。这涉及到我学习 C。有问题的程序部分缓存有关 3D 网格的法线信息。

这里按顺序调用了 3 个 vector 运算(非常标准: vector 减法以获得边 vector 、叉积和平均值),我希望尽可能快,所以我尽量避免存储任何不必要的东西在堆上......并多次复制我的结构。但是,我也知道,如果我返回指针,我将指向不再有效的内存空间。

这就是我尝试编写所有三个函数的方式(一般来说:结构复制,结构复制,而不是指针)。

typedef struct vector vector;
struct vector{
    double x,y,z;
};

vector vect(vector a, vector b){
    vector res;
    res.x = b.x - a.x; 
    res.y = b.y - a.y;
    res.z = b.z - a.z;
    return res;
}

vector cross(vector a, vector b){
    vector res;
    res.x = a.y*b.z - a.z*b.y;
    res.y = a.z*b.x - a.x*b.z;
    res.z = a.x*b.y - a.y*b.x;
    return res;
}

vector avg (vector a, vector b){
    vector res;
    res.x = (a.x + b.x)/2;
    res.y = (a.y + b.y)/2;
    res.z = (a.z + b.z)/2;
    return res;
}

这就是它的名字:

m->Tpolynormals[i] = avg(cross( vect(*p->verts[0], *p->verts[1]),
                                vect(*p->verts[1], *p->verts[2]) ),
                         cross( vect(*p->verts[2], *p->verts[3]),
                                vect(*p->verts[3], *p->verts[0]) )
                        );

这是相当有效还是有更快的方法?我知道我可以尝试并“让它发挥作用”,但在这一点上我想确保基础牢固。 - 谢谢

编辑:在上面添加了我的结构定义,正如有人明显指出的那样,呃。坐标是 double 的(这是我的 3D 包输出的),系统是 64 位的。

最佳答案

“避免(初学者的)分配错误”与“我想尽可能快”

哪个更重要?

如果代码需要尽可能快,请尝试多种方法并分析它们,看看哪种方法最适合您。你会犯错误。

vector 的大小处于边界区域,提供最佳答案的一般答案,按值或其地址传递 vector。最好两者都试一下

1) 按值传递vector。 OP 似乎很了解这一点。

vector vect(vector a, vector b){
    vector res;
    res.x = b.x - a.x; 
    res.y = b.y - a.y;
    res.z = b.z - a.z;
    return res;
}

2) 通过地址传递vector。创建中间结果位置。这似乎是OP不确定的部分。

void V_vect(vector *res, const vector *a, const vector *b){
    res->x = b->x - a->x; 
    res->y = b->y - a->y;
    res->z = b->z - a->z;
}

// usage example
vector res1;
vector res2;
V_vect(&res1, p->verts[0], p->verts[1]);
V_vect(&res2, p->verts[1], p->verts[2]);
vector res3;
V_cross(&res3, &res1, &res2);

V_vect(&res1, p->verts[2], p->verts[3]);
V_vect(&res2, p->verts[3], p->verts[0]);
vector res4;
V_cross(&res4, &res1, &res2);

V_avg(&m->Tpolynormals[i], &res3, &res4);

特别是,建议避免在下面的同一调用中重复使用内存。这可能是新手犯的错误,无论是在功能上还是在代码性能上。

V_cross(&res2, &res1, &res2);

在传递地址时加快速度的一种方法是使用restrict。这允许编译器知道调用代码正在使用指向不重叠区域的指针。这允许进行某些编译器优化。

void V_vect(vector * restrict res, const vector * restrict a, const vector * restrict b){
    res->x = b->x - a->x; 
    res->y = b->y - a->y;
    res->z = b->z - a->z;
}

使用 restrict 时,下面的第一个调用是未定义的行为,因为它与 vector 重叠。

// V_cross(&res2, &res1, &res2);  // bad
V_cross(&res4, &res1, &res2);  // good

尝试各种方法(包括 @Jonathan Leffler compound literal idea@Jonathan Leffler inline idea )并使用适合您的方法。

关于c - 在 C 中的 vector 函数序列中避免(初学者)分配错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38129062/

相关文章:

单链表上的 C 程序返回错误

javascript - 通过引用传递的参数

c - 运行时错误: to create a binary tree

c - 悬挂指针示例混淆

c - 使用 int 到 void * 转换避免竞争条件

c - 二分查找出现无限循环,为什么?

C#函数意识?

在 struct 中为 char 数组创建指针大小的内存

c - 可变长度整数数组

c++ - 在 C++ 中,如何在继续执行整个程序的同时延迟程序的一部分?