Передача постоянной матрицы - PullRequest
4 голосов
/ 27 августа 2009

Ссылаясь на этот вопрос и особенно принятый ответ лит, мне интересно, почему gcc жалуется на это:

void func(const int (*ip)[3]) {
    printf("Value: %d\n", ip[1][1]);
}

int main() {
    int i[3][3] = { {0, 1, 2} , {3, 4, 5}, {6, 7, 8} };
    func(i);
    return 0;
}

Если я исключу const, компилятор останется на месте. Я что-то не так понял? Я хотел быть уверен, что func не изменяет мой массив.

РЕДАКТИРОВАТЬ: То же самое происходит, если я определяю тип данных для моей матрицы:

typedef int Array[3][3];

void func(const Array *p) {
    printf("Value: %d\n", (*p)[1][1]);
}

int main() {
    Array a = { {0, 1, 2}, {3, 4, 5}, {6, 7, 8} };
    func(&a);
    return 0;
}

Я согласен, такой код не очень в стиле C, больше похож на C ++. В C ++ действительно не было бы проблем, если бы я определил Array как класс, содержащий все поведение матрицы.

class Array {...};

Полагаю, я не очень хорошо понимал концепцию массивов и массивов массивов в C и передачу их функциям. Есть ли просветление?

Заранее спасибо.

EDIT2: Тем временем я немного обдумал эту проблему, и она, кажется, сходится к следующему вопросу: C / C ++ неявно преобразует указатель на int в указатель на const int. Таким образом, следующие работы:

func(const int a[]) // aquivalent: func(const int *a)
{ ... }

int main() 
{
    int b[10];
    func(b);
    return 0;
}

Но C / C ++ неявно преобразует указатель на массив из n int s в указатель на массив из n const int s. Даже если массив из n int s неявно преобразуется в массив из n const int s. Этот уровень косвенности в неявном преобразовании не поддерживается. Следующее будет отклонено (по крайней мере, с предупреждением в C):

func(const int a[][n]) // aquivalent: func(const int (*a)[n])
{ ... }

int main()
{
    int b[m][n];
    func(b);
    return  0;
}

Это похоже на проблему, заключающуюся в том, что C ++ неявно преобразует шаблон для типа A в шаблон типа B, даже если A может быть неявно преобразован в B. Два шаблона имеют совершенно разные типы.

Это правильный ответ?

Ответы [ 2 ]

2 голосов
/ 27 августа 2009

Ваша i переменная представляет собой массив из 3 элементов.

Когда вы передаете его функции, внутри функции она становится указателем на первый элемент. Компилятор может добавить const либо к указателю, либо к указанному объекту: массив из 3-х элементов . Однако он не может изменить указанную вещь с массив из 3-х точек на массив из 3 констант .

Я думаю, тебе нужно сыграть самому.

#include <stdio.h>

typedef const int array_of_3_constants[3];

void func(int (* const i)[3]) {
  ++i[0][0];
  printf("Value: %d\n", i[1][1]);
}

void gunc(array_of_3_constants *i) {
  ++i[0][0];                              /* error */
  printf("Value: %d\n", i[1][1]);
}

int main(void) {
  int i[3][3] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}};
  func(i);
  func((array_of_3_constants*)i);         /* warning */
  gunc(i);                                /* warning */
  gunc((array_of_3_constants*)i);
  return 0;
}
1 голос
/ 27 августа 2009

Вам не нужно исключать const, просто передайте совместимое значение, передав аргумент в вызове func:

   func( (void *)i );

Если возможно, было бы предпочтительнее объявить i как const, но этот хак должен работать.

...