bol*_*lov 144 c++ gets input standards-compliance
Coderbyte是一个在线编码挑战网站(我在2分钟前找到了它)。
您遇到的第一个C ++挑战有一个您需要修改的C ++框架:
Run Code Online (Sandbox Code Playgroud)#include <iostream> #include <string> using namespace std; int FirstFactorial(int num) { // Code goes here return num; } int main() { // Keep this function call here cout << FirstFactorial(gets(stdin)); return 0; }
如果你稍微熟悉C ++的第一件事*在你的眼睛持久性有机污染物是:
int FirstFactorial(int num);
cout << FirstFactorial(gets(stdin));
Run Code Online (Sandbox Code Playgroud)
因此,好的,代码调用gets从C ++ 11开始不推荐使用,而从C ++ 14开始删除,这本身就是不好的。
但后来我意识到:gets是类型char*(char*)。因此,它不应该接受FILE*参数,并且结果不能代替int参数使用,但是...不仅可以编译时没有任何警告或错误,而且可以运行并将实际的正确输入值传递给FirstFactorial。
在此特定站点之外,代码无法编译(如预期的那样),那么这里发生了什么?
*实际上第一个是,using namespace std但这与我在这里的问题无关。
小智 172
我是Coderbyte的创始人,也是创建此gets(stdin)hack的人。
关于此帖子的评论是正确的,因为它是一种查找和替换的形式,所以让我解释一下为什么我真的很快做到了。
在我最初创建网站的那天(大约2012年),它仅支持JavaScript。无法在浏览器中运行的JavaScript中“读取输入”,因此会有一个函数foo(input),我使用readline()Node.js中的函数像这样调用它foo(readline())。除了我还很小的时候,我并不了解,所以从字面上看,我只是readline()在运行时替换了输入。因此foo(readline())成为JavaScript foo(2)或foo("hello")对JavaScript正常运行。
在2013/2014年左右,我添加了更多的语言,并使用了第三方服务来在线评估代码,但是很难对正在使用的服务执行stdin / stdout,因此我坚持使用相同的语言傻瓜式查找和替换例如Python,Ruby,最后是C ++,C#等。
时至今日,我在自己的容器中运行代码,但从未更新stdin / stdout的工作方式,因为人们已经习惯了怪异的hack(有些人甚至在论坛上发布了解释如何解决它的方法)。
我知道这不是最佳实践,对于学习新语言的人来说,看到这样的黑客行为是无济于事的,但是这个想法是让新程序员完全不用担心阅读输入,而只是专注于编写算法来解决问题。问题。几年前,有关编码挑战站点的一个普遍抱怨是,新程序员会花大量时间来弄清楚如何stdin从文件中读取或读取文件中的行,因此我希望新的编码器避免在Coderbyte上出现此问题。
我将尽快更新整个编辑器页面以及默认代码并stdin阅读语言。希望那时C ++程序员会喜欢更多使用Coderbyte的:)
bol*_*lov 112
我很感兴趣 因此,是时候放下调查镜了,并且由于我无权访问编译器或编译标志,因此我需要发挥创造力。另外,由于此代码没有意义,因此对每个假设都提出质疑并不是一个坏主意。
首先,让我们检查的实际类型gets。我有一个小窍门:
template <class> struct Name;
int main() {
Name<decltype(gets)> n;
// keep this function call here
cout << FirstFactorial(gets(stdin));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
看起来...正常:
Run Code Online (Sandbox Code Playgroud)/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;
}
Run Code Online (Sandbox Code Playgroud)
这给了我们:
Run Code Online (Sandbox Code Playgroud)/tmp/286775780/Main.cpp:15:21: error: implicit instantiation of undefined template 'Name<int>' Name<decltype(8)> n; ^
最后,我们得到了一些东西:decltype(8)。因此,整个内容gets(stdin)在文本上被输入(8)替换。
事情变得奇怪了。编译器错误继续:
Run Code Online (Sandbox Code Playgroud)/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;
Run Code Online (Sandbox Code Playgroud)
它编译。
但
std::integral_constant<int, gets(stdin)> n; // OK
std::integral_constant<int, gets(stdin)> n2; // ERROR wtf??
Run Code Online (Sandbox Code Playgroud)
与该n2行的预期错误不符。
再一次,几乎任何修改main都会使该行cout << FirstFactorial(gets(stdin));吐出预期的错误。
而且stdin实际上似乎是空的。
因此,我只能得出结论,并推测他们有一个小程序可以解析源,并gets(stdin)在实际将其输入编译器之前尝试(较差)替换为测试用例的输入值。如果有人有更好的理论或实际上知道他们在做什么,请分享!
这显然是非常糟糕的做法。在研究这个问题时,我发现这里至少有一个问题(示例),因为人们不知道那里有一个站点可以这样做,所以他们的回答是“不要使用getsuse ...代替”,这的确是一个很好的建议,但只会使OP更加混乱,因为任何从stdin进行有效读取的尝试都将在此站点上失败。
gets(stdin)无效的C ++。这个特定网站使用的是一个头(出于什么原因我无法弄清楚)。如果要继续在网站上提交(我既不认可也不不认可),则必须使用此结构,否则该结构将无济于事,但请注意它很脆弱。几乎所有对的修改main都会吐出一个错误。在此站点之外,请使用常规的输入阅读方法。
alt*_*gel 64
我main在Coderbyte编辑器中尝试了以下功能:
std::cout << "gets(stdin)";
Run Code Online (Sandbox Code Playgroud)
gets(stdin)字符串文字内出现神秘神秘的代码段的位置。这不应该被任何东西(甚至是预处理器)进行转换,任何 C ++程序员都应该期望此代码将确切的字符串打印gets(stdin)到标准输出中。但是,当编译并在coderbyte上运行时,我们看到以下输出:
8
Run Code Online (Sandbox Code Playgroud)
8从编辑器下方便的“输入”字段直接获取值的位置。
由此可见,该在线编辑器正在对源代码执行盲目查找和替换操作,gets(stdin)用用户的“输入” 代替外观。我个人认为这是对语言的滥用,这比粗心的预处理器宏还要糟糕。
在一个在线编码挑战网站的上下文中,我对此感到担心,因为它会讲授非常规,非标准,无意义且至少是不安全的做法(例如)gets(stdin),并且这种方式在其他平台上无法重复。
我敢肯定,这不可能是这个很难只使用std::cin,只是流输入到程序。
| 归档时间: |
|
| 查看次数: |
7159 次 |
| 最近记录: |