OpenCL仅提供使用C99规范访问单维数组的权限。然而,我的问题是在二维空间中我在主机端使用二维数组
我想使用C宏来获取元素A[i][j]
,而不是通过计算索引来降低代码的可读性。不幸的是,我在这方面相当糟糕,而且很少有c语言的经验。我想我对它是如何完成的有一个大致的想法,但如果有人能批评它,我将不胜感激。
应该是这样的:
#define 2d_access(u, y, x) (u[y][x])
,其中u是矩阵,y是行,x是列,宏将返回u[y][x]
值
矩阵是静态分配的,所以宏将有一个WIDTH组件。
#define 2d_access(u, y, x) (u[y * WIDTH] + x])
由于到目前为止所有的答案都依赖于恒定的宽度,因此这里有一个(重量级的)任意宽度列的解决方案:
#define matrix_type(t) struct { size_t width; t array[]; }
#define matrix_alloc(t, w, h) malloc(offsetof(matrix_type(t), array[(w) * (h)]))
#define matrix_init(m, t, w, h)
matrix_type(t) *m = matrix_alloc(t, w, h);
if(!m) matrix_alloc_error(); else m->width = (w);
#define matrix_index(m, w, h) m->array[m->width * (w) + (h)]
// redefine if you want to handle malloc errors
#define matrix_alloc_error()
用free
释放数组
当然,您也可以为高度添加一个字段,并执行边界检查等操作。您甚至可以将这些编写为实际的函数,或者使用宏来自动声明struct
类型,这样您就不必为所有内容使用匿名struct
类型。如果需要在堆栈上使用,可以使用alloca
,但要以可移植性为代价。
如果你有一个固定的矩阵大小,你可以使用一些转换技巧来实现"原生"2D索引(通过[]
操作符):
#define CAT_(x, y) x##y
#define CAT(x, y) CAT_(x, y)
#define MANGLE(x) CAT(x, _hidden_do_not_use_0xdeadbeef_)
#define matrix_init(m, t, w, h)
t MANGLE(m)[(w) * (h)];
t (*m)[(w)] = (void *)MANGLE(m);
// because of the funky typing, `m[0][1]` does what you'd expect it to.
请注意,与其他解决方案不同,这创建了第二个变量,这可能不是很干净,但我认为我使用了一个非常清晰的mangling方法,因此在实践中它不会妨碍。
为您正在使用的每个数组定义一个宏,这样您就可以使它看起来完全像一个2D数组访问。因此,给定数组A
,您将定义:
#define A(r, c) (A[(r)*WIDTH + (c)])
注意替换值周围的圆括号。这将处理替换为表达式的情况,如A(i + 1, j)
。如果没有括号,这将展开为A[i + 1*WIDTH + j]
,这不是您想要的:
A[i + 1*WIDTH + j] = A[WIDTH + i + j] != A[(i + 1)*WIDTH + j]
为了避免第二个参数出现同样的问题,两个参数在替换文本中都用圆括号括起来。
没有批评,你已经给出了解决方案:
#define access_2d(u, y, x) (u[(y) * WIDTH + (x)])
好吧,也许我的想法不同,但我将定义为
// x before y
#define access_2d(u, x, y) (u[(y) * WIDTH + (x)])
这并没有更好,只是一个偏好。