C 定义返回不兼容类型但不可访问的函数

C 定义返回不兼容类型但不可访问的函数,c,language-lawyer,c99,C,Language Lawyer,C99,阅读C99标准后,我在下面找不到任何禁止定义函数f的章节: struct s { double d; }; int f() { if (0) return (struct s){.d = 3.14}; // There is intentionally no return statement of type int, which is valid } int main() { f(); return 0; } 特别是,应该定义该程序的行为,因为返回值(a)从未达到,并且(b

阅读C99标准后,我在下面找不到任何禁止定义函数
f
的章节:

struct s { double d; };

int f() {
  if (0) return (struct s){.d = 3.14};
  // There is intentionally no return statement of type int, which is valid
}

int main() {
  f();
  return 0;
}
特别是,应该定义该程序的行为,因为返回值(a)从未达到,并且(b)从未使用,即使已经达到

尽管如此,我的大多数编译器(GCC、Clang和CompCert)都阻止编译此程序,错误
从结果类型为“int”的函数返回“struct s”
。我确实设法用tcc编译了它,但我不知道这是否主要是因为运气(即缺乏验证)

有人能确认这个程序是否在语法上是C99有效的,并且它的行为是完全定义好的,或者指出标准禁止它的地方吗

实际上,我更希望我的编译器拒绝它,但例如,某些宏定义可能会生成类似于此定义的代码,因此,如果这些程序有效,那么接受这些程序实际上是有用的

背景

下面是我可以找到的C99标准的相关摘录,以及我关于为什么它们不应该禁止我的程序在语法上有效和语义上定义良好的理由:

§6.8.6.4返回语句

§6.8.6.4.1带有表达式的返回语句不得出现在返回类型为void的函数中。没有表达式的返回语句只能出现在返回类型为void的函数中

在我的代码中,我们有一个non-
void
函数和一个non-
void
返回,所以一切看起来都很好

§6.8.6.4.3如果执行带有表达式的返回语句,则表达式的值将作为函数调用表达式的值返回给调用方。如果表达式的类型与它出现的函数的返回类型不同,则该值将被转换,就像通过赋值给具有函数返回类型的对象一样

由于return语句从未执行过,因此上述内容不适用

§6.9.1功能定义

§6.9.1.12如果到达终止函数的},并且调用方使用了函数调用的值,则行为未定义


调用方不使用函数调用的结果,因此应该定义行为。

“如果表达式的类型与它出现的函数的返回类型不同,则将值转换为具有函数返回类型的对象。”是一个独立的句子。它不以“如果执行了带有表达式的返回语句”为条件,因此甚至适用于您的代码。我敢肯定,您已经知道,通过赋值进行转换意味着不兼容类型会导致编译时错误。

一般来说,您不应该期望编译器接受
if(always_false){invalid_code;}
,因为编译器可能无法说服自己
always_false
总是false。即使可以,它的类型检查阶段也不应该依赖于这种类型的分析和没有返回值的最终
}
实际上是两个独立的问题,最好是两篇文章。无论如何,这是一个深思熟虑的问题。在ubuntu linux 14.04上,使用gcc,参数为:
-Wall-Wextra-pedantic-std=c99
编译器输出两条消息:1)…4:`0:当返回类型“struct s”但预期为“int”时,错误不兼容类型。2) …6:1:警告:控件到达非void函数[-Wreturn type]的末尾,因此发布的代码存在两个主要问题。任何现代编译器(尤其是使用c99兼容的编译器)都会告诉您同样的情况。当编译器说代码错误时,你可以相信TurboC’是一个古老的编译器,适合它的时代,但现在不是了。对c99标准的分析,因为它与发布的代码有关,是有缺陷的。让我们记住,发布的代码返回的是一个struct,而不是double。通常,无法将结构分配给int。如果代码实际将double分配给int,则发布的代码的该部分将是有效的。