【问题标题】:macro for simulating access two dimensional array in C用于在 C 中模拟访问二维数组的宏
【发布时间】:2011-10-30 23:46:41
【问题描述】:

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

【问题讨论】:

    标签: c multidimensional-array opencl


    【解决方案1】:

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

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

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

    【讨论】:

    • 感谢不要用硬编码的解决方案污染互联网。
    【解决方案2】:

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

    为了避免第二个参数出现同样的问题,在替换文本中都用括号括起来。

    【讨论】:

    • 快速提问,在宏名和扩展名中使用同名A 是否安全?通过快速测试,它看起来很好。
    【解决方案3】:

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

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

    好吧,也许我的想法不同,但我会把它定义为

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

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

    【讨论】:

    • 这只适用于所有数组都具有恒定宽度的情况,这可能会破坏使用二维数组的意义。
    • 如果不同的数组具有不同的宽度,可能值得将它们封装到包含指针和宽度的struct 中,并更改宏以使其在所述struct 上运行。跨度>
    • @Matteo - 这实际上是我刚刚写的答案。
    • 我假设 WIDTH 是一个常数。看起来像。
    • @Rudy - 我想这不是毫无意义的。只是,对于固定宽度,您可以通过 [] 运算符和 type arr[w * h] = {0}; type (*ptr)[w] = (void *)arr; 实现 2D 索引,诚然,这看起来很麻烦,但可以隐藏在宏后面。
    猜你喜欢
    • 2016-12-03
    • 2016-08-24
    • 2017-11-24
    • 2013-06-29
    • 2021-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-03
    相关资源
    最近更新 更多