Операнды не совместимы по присваиванию - PullRequest
4 голосов
/ 11 мая 2019

У меня есть следующий код:

struct something {
  char *(*choices)[2];
};
char* arr[2] = {"foo", "bar"};

int main(void) {
  struct something obj;
  obj.choices = &arr;
  return 0;
}

Когда я компилирую это с помощью обычного компилятора C (gcc), я не получаю ошибок.Тем не менее, я компилирую для Z80, и он вызывает ERROR (152) Operands are not assignment compatible, который описывается как:

Была предпринята попытка присвоить значение, тип которого не может быть переведен в тип назначения.

Я не понимаю, как могут различаться типы &arr и char *(*choices)[2].Что я могу сделать, чтобы это исправить?

(я использую компилятор Zilog z80, который является частью ZDS 5.2.0 )

Ответы [ 2 ]

4 голосов
/ 11 мая 2019

Возможно, это какая-то странная ошибка компилятора.Этот код прекрасно компилируется:

struct something {
  char *** choices;
};

char * arr[2] = {"foo", "bar"};

int main(void) {
  struct something obj;
  obj.choices = &arr;
  return 0;
}

И я боюсь, что это единственный обходной путь, который наиболее совместим с оригинальной идеей.

2 голосов
/ 22 мая 2019

Поддержка Zilog утверждает, что это на самом деле не ошибка компилятора, и что исходный код не компилируется, поскольку он не является строго ANSI C. Он принят GCC, потому что компилятор "снисходительный" и добавил несколькобольше правил синтаксиса, выходящих за рамки спецификации ANSI C.Вот полный ответ:

Компилятор GCC, хотя и очень хороший, не обязательно является идеальной реализацией стандарта C.За прошедшие годы я видел несколько случаев, когда широко используемые компиляторы, такие как MSVC ++ и, реже, GCC принимают синтаксис, который не является строго ANSI C, когда этот синтаксис кажется безвредным квази-расширением стандарта C и его опасности нет.интерпретируется в каком-то альтернативном, законном значении.Это может быть еще одним примером этого.

В этом есть тонкость синтаксиса C, и вот мое понимание этого вопроса, а также почему GCC допускает оригинальный синтаксис клиента.Как только указатель функции, например, правильно определенная переменная fnPtr, получил определение, ему разрешается вызывать его без предшествующего * оператора косвенного обращения с помощью выражения, подобного

result = fnPtr(x); // This is legal syntax…

result = (*fnPtr) (x); // … even though this is “more correct”

Причина, по которой допускается 1-й синтаксис, показанный выше, заключается в том, что скобки, содержащие параметр x, рассматриваются как оператор C, тип которого «указатель на функцию».Таким образом, наличие этих скобок делает оператор косвенного обращения ненужным, когда указатель функции фактически используется для вызова функции.Однако в случае, подобном этому пользовательскому коду, когда вы просто используете указатель функции в операторе присваивания, это не вступает в игру, и поэтому эти операнды, на самом деле, не являются строго совместимыми по присваиванию.Однако вряд ли можно обвинить пользователя, который не является экспертом по языку экспертов, за то, что он ожидал, что если указатель функции можно использовать без * в одном месте, он также должен быть приемлемым в других контекстах.Возможно, именно поэтому разработчики GCC решили принять синтаксис пользователя.

Вот альтернативная версия, которая компилируется:

struct something {
  char *(*choices[2]);
};

char* arr[2] = {"foo", "bar"};

int main(void) {
  struct something obj;
  *obj.choices = &arr;
  return 0;
}
...