【问题标题】:GCC Incompatible pointer type using a typedef使用 typedef 的 GCC 不兼容的指针类型
【发布时间】:2016-01-27 08:47:41
【问题描述】:

我有一些在 GCC 4.8.4 下编译良好的代码。我最近升级了我的系统,现在有了 GCC 5.2.1,我收到了关于指针类型不兼容的警告。我已将问题提取为一个重现错误的小示例:

typedef const double ConstSpiceDouble;
void foo(const double (*)[3]); 

int main(int argc, char **argv) {
  double a[3][3] = {{1,2,3},{1,2,3},{1,2,3}};

  foo((ConstSpiceDouble (*)[3])a);

  return 0;
}

在实际代码中,typedef、函数定义和类型转换都在我无法控制的库中,否则我只会修复转换和要匹配的函数。这是我从编译器得到的消息:

$ gcc -Werror -c test.c
test.c: In function ‘main’:
test.c:9:7: error: passing argument 1 of ‘foo’ from incompatible pointer type [-Werror=incompatible-pointer-types]
   foo((ConstSpiceDouble (*)[3])a);
       ^
test.c:4:6: note: expected ‘const double (*)[3]’ but argument is of type ‘const ConstSpiceDouble (*)[3] {aka const double (*)[3]}’
 void foo(const double (*)[3]);
      ^
cc1: all warnings being treated as errors

来自 gcc 的注释尤其令人不安,因为它似乎承认这两种类型是相同的,但它仍然抱怨。

【问题讨论】:

  • GCC 5.2.0 上顺利编译(以及 Clang 3.7.0)。我倾向于编译器错误。
  • 很高兴知道它在 5.2.0 上编译,这绝对将版本可能性限制在 5.2.1。
  • 你说“5.2.1”是什么意思?此版本尚未正式发布:svn: URL 'svn://gcc.gnu.org/svn/gcc/tags/gcc_5_2_1_release' doesn't exist
  • $ gcc --version gcc (Ubuntu 5.2.1-22ubuntu2) 5.2.1 20151010 版权所有 (C) 2015 Free Software Foundation, Inc. 这是免费软件;查看复制条件的来源。没有保修;甚至不是为了适销性或适合特定目的。
  • @MM,关于编译器版本毫无疑问,我对 Ubuntu 在他们的 15.10 版本中放置了一个未发布的 GCC 感到有点恼火,但为了讨论起见,让我们假设我对 Ubuntu 发布决策的控制非常少,但仍然需要在其中编译软件。 (-= 我刚刚尝试了 -std=c11 标志,它没有任何效果。无论如何,如果这是一个 gcc 错误,最好在它发布之前找到它,希望下一个 Ubuntu 版本,这将是LTS,将有一个固定的 gcc。如果发生这种情况,那么从长远来看,这种暂时的恶化是值得的。

标签: c pointers gcc


【解决方案1】:

这里和其他地方的共识似乎是 GCC 对 const 和 typedef 做了一些意想不到的事情。我不知道意外必然等同于错误,但这是由 GCC 开发人员确定的。

我通过为函数调用定义一个宏来解决我的编译问题,该函数调用修复了库中的不匹配类型转换。我通常不喜欢修补库内部,但宏允许我不触及实际的库头并在我自己的代码中定义它,以便将来对其进行注释,并且该代码的测试覆盖率应该是一个合理的预警信号,如果底层库以这样一种方式发生变化,即宏在路上会破坏某些东西。

这与其说是“解决”不如说是“解决”,但任何进一步的见解都可能需要来自 GCC 开发人员。

【讨论】:

  • 我很想看到那个宏摘录
【解决方案2】:

如果您键入 cast 'a' 为 ConstSpiceDouble,则 GCC 对 const 和 typedef 做了一些意想不到的事情,最终类型变为 'const const double'。这您可以在错误消息“const ConstSpiceDouble”中看到,它等同于“const const double”,这不起作用。

解决方案是在将 'a' 参数传递给 foo 函数之前说 'a' 是 const double 或说 'a' 是 ConstSpiceDouble

typedef const double ConstSpiceDouble;
void foo(const double (*)[3]); 

int main(int argc, char **argv) {

  const double a[3][3] = {{1,2,3},{1,2,3},{1,2,3}};
  // or ConstSpiceDouble a[3][3] = {{1,2,3},{1,2,3},{1,2,3}};

  foo(a);

  return 0;
}

'const' 前置似乎是最新版本 gcc 中的一个新功能,但我不确定:(

【讨论】:

  • 不幸的是,在实际代码中,'a' 本身不能是 const,因为它在函数调用之前设置矩阵时被修改。为了清楚起见,我只是提取了重现错误的最少代码量。
  • 这个答案的第一段是错误的。 C 中没有“自动前置”。建议的替代代码可以编译,但它没有帮助,因为 OP 需要 main 中的数组是非常量的。
  • 去掉了“自动前置”部分
  • 需要明确的是,根据 C 标准(6.7.3/5),“const const double”应该与“const double”的类型相同,这将是一个 gcc 错误处理两者不同。 (但原始代码实际上并没有在任何地方生成“const const double”,错误消息似乎表明 gcc 正在进一步搞砸事情)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多