макрос для моделирования доступа двумерного массива в C - PullRequest
10 голосов
/ 20 августа 2011

OpenCL предлагает доступ только к одномерным массивам, используя спецификации C99.Моя проблема, однако, в двух измерениях, и я использую двумерные массивы на стороне хоста

Вместо того, чтобы делать мой код менее читаемым путем вычисления индексов, я хотел бы использовать макрос C для получения элемента A[i][j].К сожалению, я довольно плох в этом и имею небольшой опыт в C. Я думаю, что у меня есть общее представление о том, как это делается, но если кто-то может критиковать, это будет оценено.

Это будет что-то вроде:

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

, где u - матрица, y - строка, а x - столбец, а макрос вернет значение в u[y][x]* 1010.*

Матрица размещена статически, поэтому макрос будет иметь компонент WIDTH.

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

Ответы [ 3 ]

7 голосов
/ 20 августа 2011

Поскольку все ответы до сих пор основаны на постоянной ширине, вот (тяжелое) решение для столбцов произвольной ширины:

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

Обратите внимание, что в отличие от другого решения, это создает вторую переменную, которая, вероятно, не очень чиста, но я думаю, что я использовал довольно четкий метод искажения, поэтому он выиграл 'мешать на практике.

6 голосов
/ 20 августа 2011

Еще чище было бы определить макрос для каждого массива, который вы используете, так что вы можете сделать так, чтобы он выглядел точно так же, как доступ к двумерному массиву.Итак, учитывая массив 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]

Чтобы избежать той же проблемы со вторым аргументом, оба заключены в скобки в тексте подстановки.

2 голосов
/ 20 августа 2011

Нет критики, вы уже дали решение:

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

ОК, может быть, я думаю по-другому, но я бы определил его как

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

Это не лучше,просто предпочтение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...