C中模拟访问二维数组的宏

发布于 2024-11-30 15:36:08 字数 429 浏览 1 评论 0原文

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])

OpenCL only offers access to single dimensional arrays using the C99 specs. My problem however is in two dimensions and I am using two dimensional arrays on the host side

Rather than making my code less readable by calculating indices, I would like to use a C macro to get element A[i][j]. Unfortunately I'm rather bad at this and have little experience in C. I think I have the general idea of how it is done, but if someone could critique it would be appreciated.

It would be something like:

#define 2d_access(u, y, x) (u[y][x])

where u is the matrix, y is the row, and x is the column and the macro would return the
value at u[y][x]

The matrix is allocated statically so the macro would have a WIDTH component.

#define 2d_access(u, y, x) (u[y * WIDTH] + x])

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

云归处 2024-12-07 15:36:08

由于到目前为止所有答案都依赖于恒定宽度,因此这里有一个针对任意宽度列的(重量级)解决方案:

#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.

请注意,与其他解决方案不同,这会创建第二个变量,这可能不是很干净,但我认为我使用了一种非常清晰的修饰方法,因此在实践中不会妨碍。

Since all the answers so far rely on a constant width, here's a (heavyweight) solution for arbitrary width columns:

#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()

Just deallocate the array with free.

Of course, you can add a field for height as well and do bounds checking, among other things. You could even write these as actual functions, or use a macro to automatically declare struct types so you don't have to use an anonymous struct type for everything. If you need it on the stack, you could use alloca at the cost of portability.

If you have a constant matrix size, you can use some casting hacks to achieve "native" 2D indexing (via the [] operator):

#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.

Note that, unlike the other solution, this creates a second variable, which is probably not very clean, but I think I used a pretty clear mangling method so it won't get in the way in practice.

提赋 2024-12-07 15:36:08

更干净的方法是为您使用的每个数组定义一个宏,这样您就可以使其看起来与二维数组访问完全相同。因此,给定数组 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]

为了避免第二个参数出现相同的问题,两者都包含在括号中在替换文本中。

Even cleaner would be to define a macro for each array you're using, so you can make it look exactly like a 2D array access. So, given the array A, you would define:

#define A(r, c) (A[(r)*WIDTH + (c)])

Note the parentheses around the substituted values. This handles cases where the substitution is an expression, like A(i + 1, j). Without the parentheses, this would expand to A[i + 1*WIDTH + j], which is not what you want:

A[i + 1*WIDTH + j] = A[WIDTH + i + j] != A[(i + 1)*WIDTH + j]

In order to avoid the same problem with the second argument, both are enclosed in parentheses in the substitution text.

黑白记忆 2024-12-07 15:36:08

没有批评,你已经给出了解决方案:

#define access_2d(u, y, x) (u[(y) * WIDTH + (x)])

好吧,也许我的想法不同,但我将其定义为

// x before y
#define access_2d(u, x, y) (u[(y) * WIDTH + (x)])

但这并不是更好,只是一种偏好。

No critique, you already gave the solution:

#define access_2d(u, y, x) (u[(y) * WIDTH + (x)])

OK, maybe I think differently, but I would define it as

// x before y
#define access_2d(u, x, y) (u[(y) * WIDTH + (x)])

That is not better, though, just a preference.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文