操作数与赋值不兼容

Operands are not assignment compatible

我有以下代码:

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,它被描述为:

An attempt was made to assign a value whose type cannot be promoted to the type of the destination.

我不明白 &arrchar *(*choices)[2] 的类型有何不同。我该怎么做才能解决这个问题?

(我正在使用 Zilog z80 编译器,它是 ZDS 5.2.0 的一部分)

这可能是某种奇怪的编译器错误。此代码编译正常:

struct something {
  char *** choices;
};

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

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

而且我担心这是唯一最符合原始想法的解决方法。

Zilog 支持声称它实际上不是编译器错误,并且原始代码无法编译,因为它不是严格的 ANSI C。它被 GCC 接受,因为编译器是 "lenient" 并且添加了一些超出 ANSI C 规范的语法规则。这是完整的回复:

The GCC compiler, while very good, is not necessarily a perfect implementation of the C Standard. Over the years I have seen a few cases where widely used compilers, like MSVC++ and, less frequently, GCC accept syntax that is not strictly ANSI C when that syntax seems to be a harmless quasi-extension of standard C and there’s no danger of its being interpreted in some alternate, legitimate meaning. This may be another instance of that.

There’s a fine point of C syntax involved and here is my understanding of that point, along with why perhaps GCC allows the customer’s original syntax. Once a function pointer, e.g. a properly defined variable fnPtr, has acquired a definition, it is allowed to invoke it without the preceding * indirection operator through an expression like

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

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

The reason why the 1st syntax shown above is allowed is that the parentheses enclosing parameter x are regarded as a C operator whose type is “pointer to function”. So the presence of those parentheses makes the indirection operator unnecessary when the function pointer is actually used for making a function call. However, in a case like this customer code where you are just using the function pointer in an assignment statement, this doesn’t come into play and so those operands are not, in fact, strictly assignment compatible. However, a user who is not an expert language wrangler can hardly be blamed for expecting that if the function pointer can be used without the * in one place, it should also be acceptable in other contexts. This might be why the GCC developers have apparently decided to accept the user’s syntax.

这是编译的替代版本:

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

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

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