【问题标题】:Incomplete types in return-type and parameters of a function declared but not defined声明但未定义的函数的返回类型和参数中的不完整类型
【发布时间】:2021-03-23 04:02:20
【问题描述】:

以下代码是有效的 C 吗? (godbolt)

typedef struct none none;
none f(none, none);

需要明确:标识符f 永远不会出现在翻译单元中 再次,函数本身从未定义,即使在另一个 翻译单元。

【问题讨论】:

  • 你试过编译吗? (如果编译 - 有效,否则 - 无效)
  • @sergeyrar 我不是在询问特定编译器是否按原样接受代码。有些会,有些不会。我问的是从标准的角度来看它是否有效。注意language-lawyer 标签。
  • 出于好奇,哪些编译器接受和不接受它?您确定他们都打算遵守相同的标准吗?还没找到不接受的。
  • @NateEldredge gcc、clang 等接受代码。 cparser(git,不在 Godbolt 上)不接受它。它抱怨作为参数的类型不完整:cparser:“错误:匿名'参数'有不完整的类型”。
  • 有趣:在 RHEL 7.4 上运行的 GCC 10,2.0 接受代码,即使带有选项 gcc -pedantic -pedantic-errors -Wall -Werror -Wextra -std=c18 …。如果您尝试在源文件中使用或实现该函数,那么错误是正确的——并且 GCC 会发现它。我认为有争论cparser 是正确的并且GCC 有疏忽的余地。我不确定一个符合标准的程序是否能发现问题——如果它不能在符合标准的编译器中编译,它就不是符合标准的代码。

标签: c function language-lawyer declaration incomplete-type


【解决方案1】:

C17 标准明确规定允许参数具有不完整类型:

(6.7.6.3 (12)) 如果函数声明符不是该函数定义的一部分,则参数可能不完整 类型并可以在其声明符说明符序列中使用[*] 表示法来指定变量 长度数组类型。

所以 cparser 在此基础上拒绝代码是错误的。

至于返回类型,无论哪种方式似乎都没有明确的说法。 cppreference 说“函数的返回类型 [...] 必须是 complete 非数组对象类型或 void 类型”但我在标准中找不到相应的要求。该标准确实在“函数定义”下的 6.9.1 (3) 中说“函数的返回类型应为 void 或数组类型以外的完整对象类型”,但我认为这仅指定义。同样,6.5.2.2(1) 要求被调用的函数必须具有完整的返回类型或void

所以我认为声明中允许不完整的返回类型,只要函数没有被定义或调用。但很难确定。

【讨论】:

  • “[...] 6.9.1 (3) [...] 但我认为这仅指定义。”我也是这么读的,但是代码的有效性取决于我的另一个未知数:函数声明是否需要最终定义(可能在另一个 TU 中)?
  • @nebel:我认为不会。函数f 使用外部链接声明,并且 6.9(5) 说“如果在表达式中使用了使用外部链接声明的标识符(而不是作为 sizeof 或 _Alignof 运算符的操作数的一部分,其结果是整数常量),在整个程序的某处,标识符的外部定义应该只有一个;否则,不应超过一个。”在这里,我们处于“否则”的情况下,因此允许零定义。
猜你喜欢
  • 2018-07-05
  • 2018-05-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-18
  • 1970-01-01
  • 2017-05-31
  • 2012-02-16
相关资源
最近更新 更多