我很感兴趣。现在是时候戴上调查眼镜了,由于我没有访问编译器或编译标志的权限,所以我需要发挥创意。此外,由于这段代码毫无意义,质疑每个假设都不是一个坏主意。
首先,让我们检查gets
的实际类型。我有一个小技巧:
template <class> struct Name;
int main() {
Name<decltype(gets)> n;
cout << FirstFactorial(gets(stdin));
return 0;
}
这看起来很正常:
/tmp/613814454/Main.cpp:16:19: warning: 'gets' is deprecated [-Wdeprecated-declarations]
Name<decltype(gets)> n;
^
/usr/include/stdio.h:638:37: note: 'gets' has been explicitly marked deprecated here
extern char *gets (char *__s) __wur __attribute_deprecated__;
^
/usr/include/x86_64-linux-gnu/sys/cdefs.h:254:51: note: expanded from macro '__attribute_deprecated__'
# define __attribute_deprecated__ __attribute__ ((__deprecated__))
^
/tmp/613814454/Main.cpp:16:26: error: implicit instantiation of undefined template 'Name<char *(char *)>'
Name<decltype(gets)> n;
^
/tmp/613814454/Main.cpp:12:25: note: template is declared here
template <class> struct Name;
^
1 warning and 1 error generated.
gets
标记为已弃用,其签名为 char *(char *)
。但是,FirstFactorial(gets(stdin));
怎么会编译通过呢?
让我们尝试其他方法:
int main() {
Name<decltype(gets(stdin))> n;
// keep this function call here
cout << FirstFactorial(gets(stdin));
return 0;
}
这给我们带来了:
/tmp/286775780/Main.cpp:15:21: error: implicit instantiation of undefined template 'Name<int>'
Name<decltype(8)> n;
^
终于有新进展了:decltype(8)
。因此整个gets(stdin)
都被文本替换为输入(8
)。
事情变得更加奇怪。编译器错误仍然存在:
/tmp/596773533/Main.cpp:18:26: error: no matching function for call to 'gets'
cout << FirstFactorial(gets(stdin));
^~~~
/usr/include/stdio.h:638:14: note: candidate function not viable: no known conversion from 'struct _IO_FILE *' to 'char *' for 1st argument
extern char *gets (char *__s) __wur __attribute_deprecated__;
现在我们对cout << FirstFactorial(gets(stdin));
得到了预期的错误。
我检查了宏,因为#undef gets
似乎没有任何作用,所以看起来它不是宏。
但是
std::integral_constant<int, gets(stdin)> n;
它编译了。
但是
std::integral_constant<int, gets(stdin)> n; // OK
std::integral_constant<int, gets(stdin)> n2; // ERROR wtf??
在代码的n2
行没有预期的错误。
而且,对main
的几乎任何修改都会使cout << FirstFactorial(gets(stdin));
这一行输出预期的错误信息。
此外,实际上stdin
是空的。
因此,我只能推断和猜测他们有一个小程序,解析源代码并试图(很差地)用测试用例输入值替换gets(stdin)
,然后再将其馈送到编译器。如果有人有更好的理论或确切知道他们在做什么,请分享!
这显然是一种非常不好的做法。在研究这个问题时,我发现至少有一个问题在这里(example),因为人们不知道有一个网站会这样做,所以他们的答案是“不要使用gets
,使用...代替”,这确实是一个好建议,但只会让OP更加困惑,因为在这个网站上任何尝试从stdin
中读取有效数据的操作都会失败。
太长不看
gets(stdin)
在C++中是无效的。这是这个特定网站使用的噱头(我不是支持也不是反对它)。如果你想继续在这个网站上提交代码,你必须使用这个看起来没有意义的结构,但要注意它很脆弱。对main
的几乎任何修改都会导致错误。在这个网站之外,请使用常规的输入方法。
stdin
是一个FILE*
,而任何类型的指针都会转换为char*
,这是gets()
函数参数的类型。然而,在混淆C代码比赛之外,您永远不应该编写那种代码。如果您的编译器甚至接受它,请添加更多警告标志;如果您正在尝试修复具有该结构的代码库,请将警告转换为错误。 - Davislorgets(stdin)
(多了一个空格)会产生预期的 C++ 错误。 - Roman Odaisky