【问题标题】:Operands are not assignment compatible操作数不兼容赋值
【发布时间】:2019-05-11 12:44:32
【问题描述】:

我有以下代码:

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

试图分配一个类型无法提升为目标类型的值。

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

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

【问题讨论】:

  • "普通 C 编译器 (gdb)" 你的意思是这里的 gcc 而不是调试器 gdb,对吧?
  • 您似乎遇到了错误。您可能想向供应商提出错误。
  • 编译器是否声称支持 ANSI C ?
  • 那个 repo 不是编译器。编译器来自Zilog。您必须询问他们支持的 C 语言版本。
  • 也许尝试使用memcpy?如果只有sizeof(char*(*)[2]) == sizeof(void*) 你可以void *val = &arr; memcpy(&obj.choices, &val, sizeof(void*))

标签: c z80


【解决方案1】:

这可能是某种奇怪的编译器错误。这段代码编译得很好:

struct something {
  char *** choices;
};

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

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

恐怕这是唯一与原始想法最兼容的解决方法。

【讨论】:

  • obj.choices 的类型为char ***,而&arr 的类型为char*(*)[2]。赋值来自不兼容的指针类型。您可以将char ***choices 更改为char **choicesobj.choices = &arr 为`obj.choices = arr` 并在没有任何警告的情况下进行编译。
  • @KamilCuk 感谢这项工作,但是您介意解释一下这是如何工作的吗?我(非常有限)的指针知识告诉我,choices 是一个指向字符串的指针,但是我们怎么可以在那里存储一个数组呢?字符串数组是指向字符串的指针吗?
  • 规则是:类型数组被隐式转换为指向类型的指针(除了一些极端情况,例如sizeof)参见C11 6.3.2.1p3。因此char* 的数组被转换为指向char* 的指针,因此指向char**。 C 语言中的“字符串”只是 z 零字节终止 char 数组。 char* 没有什么特别之处。你不存储一个数组,&arr 是一个指向数组的指针,该数组有两个指向char 的指针,即。 char*(*)[2]arr 具有 2 个指向 char 的指针的数组类型,但隐式转换为指向 char 的指针的指针。
【解决方案2】:

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

GCC 编译器虽然非常好,但不一定是完美的 C标准的实施。这些年来,我见过一些 广泛使用的编译器的情况,例如 MSVC++,以及不太频繁使用的编译器, 当语法似乎不是严格的 ANSI C 时,GCC 接受语法 是标准 C 的无害准扩展,没有危险 它被解释为某种替代的、合法的含义。这 可能是另一个例子。

涉及到 C 语法的一个要点,这是我的理解 在那一点上,以及为什么 GCC 可能允许客户的 原始语法。一旦一个函数指针,例如一个正确定义的 变量fnPtr,已获取定义,允许调用 通过表达式没有前面的 * 间接运算符 喜欢

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

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

上面显示的第一种语法被允许的原因是 括号括起来的参数 x 被认为是一个 C 运算符,其 type 是“函数指针”。所以这些括号的存在 使函数指针时不需要间接运算符 实际上用于进行函数调用。但是,在这样的情况下 这个客户代码,您只是在其中使用函数指针 赋值语句,这不起作用,所以那些 实际上,操作数不是严格赋值兼容的。然而,一个 非专业语言管理员的用户很难受到指责 期望如果函数指针可以在没有 * 的情况下使用 一个地方,它在其他情况下也应该是可以接受的。这有可能 这就是为什么 GCC 开发人员显然决定接受用户的 语法。

这是一个可以编译的替代版本:

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-09
    • 2013-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-02
    • 1970-01-01
    相关资源
    最近更新 更多