函数声明中返回类型和参数的不完整类型未定义。

3
以下代码是否为有效的C语言?(godbolt)
typedef struct none none;
none f(none, none);

清楚地说,标识符f在翻译单元中不再出现,并且该函数本身也从未被定义,甚至没有在另一个翻译单元中定义。

你尝试编译过它吗?(如果编译成功则有效,否则无效) - manish ma
@sergeyrar,我不是在问特定的编译器是否接受代码。有些可以,有些不行。我在问的是从标准的角度来看它是否有效。请注意language-lawyer标签。 - nebel
出于好奇,哪些编译器接受它?您确定它们都打算遵守同一标准吗?我还没有找到任何不接受它的编译器。 - Nate Eldredge
有趣的是:GCC 10.2.0在RHEL 7.4上运行时接受了代码,即使使用选项gcc -pedantic -pedantic-errors -Wall -Werror -Wextra -std=c18 …。如果您尝试在源文件中使用或实现该函数,则错误是正确的,而GCC会发现它。我认为有理由认为cparser是正确的,而GCC则存在疏忽。但是,如果无法在符合规范的编译器中编译,则不符合规范的代码不能解决问题。 - Jonathan Leffler
1个回答

3
C17标准明确规定参数可以有不完整类型。如果函数声明符不是该函数的定义的一部分,则参数可以具有不完整类型,并且可以在其声明符规范序列中使用[*]符号来指定可变长度数组类型。因此,cparser拒绝代码是错误的。
至于返回类型,似乎没有明确的陈述。cppreference表示,“函数的返回类型必须是完整的非数组对象类型或void类型”,但我找不到标准中相应的要求。标准在6.9.1(3)“函数定义”下说,“函数的返回类型应为void或完整的非数组对象类型”,但我认为这只适用于定义。同样,6.5.2.2(1)要求被调用的函数必须具有完整的返回类型或void。
因此,我的意见是在声明中允许使用不完整的返回类型,只要函数没有被定义或调用。但很难确定。

[...] 6.9.1(3)[...]但是我认为它只涉及到定义。我也是这样理解的,但是对于代码的有效性,还有一个未知因素:函数声明是否需要最终的定义(可能在另一个TU中)? - nebel
1
@nebel:我认为不是这样的。函数f被声明为外部链接,6.9(5)规定:“如果使用具有外部链接的标识符作为表达式中的一部分(除了作为sizeof或_Alignof运算符的操作数之一,其结果是整数常量),则在整个程序中必须恰好有一个外部定义该标识符;否则,不得超过一个。”在这里,我们处于“否则”的情况下,因此允许零个定义。 - Nate Eldredge

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接