問題描述
Coderbyte 是一個(gè)在線編程挑戰(zhàn)網(wǎng)站(我在 2 分鐘前發(fā)現(xiàn)它).
您遇到的第一個(gè) C++ 挑戰(zhàn)有一個(gè) C++ 框架你需要修改:
<塊引用>#include #include <字符串>使用命名空間標(biāo)準(zhǔn);int FirstFactorial(int num) {//代碼在這里返回編號(hào);}int main() {//保持這個(gè)函數(shù)調(diào)用在這里cout<<FirstFactorial(gets(stdin));返回0;}
如果您對(duì) C++ 不太熟悉,首先* 會(huì)出現(xiàn)在您的眼前:
int FirstFactorial(int num);cout<<FirstFactorial(gets(stdin));
所以,好的,代碼調(diào)用了 gets
,它自 C++11 起已被棄用,自 C++14 起被刪除,這本身就很糟糕.
但后來我意識(shí)到:gets
是 char*(char*)
類型.所以它不應(yīng)該接受 FILE*
參數(shù)并且結(jié)果不應(yīng)該用于代替 int
參數(shù),但是......不僅它編譯時(shí)沒有任何警告或錯(cuò)誤,但它運(yùn)行并實(shí)際將正確的輸入值傳遞給 FirstFactorial
.
在此特定站點(diǎn)之外,代碼無法編譯(如預(yù)期),那么這里發(fā)生了什么?
<小時(shí)>*實(shí)際上第一個(gè)是 using namespace std
但這與我在這里的問題無關(guān).
我很好奇.所以,是時(shí)候戴上調(diào)查眼鏡了,因?yàn)槲覠o法訪問編譯器或編譯標(biāo)志,所以我需要發(fā)揮創(chuàng)造力.此外,因?yàn)檫@段代碼沒有任何意義,所以對(duì)每個(gè)假設(shè)提出質(zhì)疑并不是一個(gè)壞主意.
首先讓我們檢查gets
的實(shí)際類型.我有一個(gè)小技巧:
模板結(jié)構(gòu)名稱;int main() {名稱n;//保持這個(gè)函數(shù)調(diào)用在這里cout<<FirstFactorial(gets(stdin));返回0;}
這看起來……很正常:
<塊引用>/tmp/613814454/Main.cpp:16:19: 警告:'gets' 已被棄用 [-Wdeprecated-declarations]名稱n;^/usr/include/stdio.h:638:37: 注意:'gets' 已在此處明確標(biāo)記為已棄用extern char *gets (char *__s) __wur __attribute_deprecated__;^/usr/include/x86_64-linux-gnu/sys/cdefs.h:254:51:注意:從宏__attribute_deprecated__"擴(kuò)展# 定義 __attribute_deprecated__ __attribute__ ((__deprecated__))^/tmp/613814454/Main.cpp:16:26: 錯(cuò)誤:未定義模板的隱式實(shí)例化 'Name'名稱n;^/tmp/613814454/Main.cpp:12:25:注意:模板在此處聲明模板<類>結(jié)構(gòu)名稱;^生成了 1 個(gè)警告和 1 個(gè)錯(cuò)誤.
gets
被標(biāo)記為已棄用并具有簽名 char *(char *)
.但是,FirstFactorial(gets(stdin));
是如何編譯的?
讓我們試試別的:
int main() {名稱n;//保持這個(gè)函數(shù)調(diào)用在這里cout<<FirstFactorial(gets(stdin));返回0;}
這給了我們:
<塊引用>/tmp/286775780/Main.cpp:15:21: 錯(cuò)誤:未定義模板 'Name' 的隱式實(shí)例化名稱n;^
我們終于得到了一些東西:decltype(8)
.所以整個(gè) gets(stdin)
被文本替換為輸入 (8
).
事情變得更奇怪了.編譯器錯(cuò)誤繼續(xù):
<塊引用>/tmp/596773533/Main.cpp:18:26: 錯(cuò)誤:沒有匹配的函數(shù)調(diào)用gets"cout<<FirstFactorial(gets(stdin));^~~~/usr/include/stdio.h:638:14:注意:候選函數(shù)不可行:第一個(gè)參數(shù)沒有從struct _IO_FILE *"到char *"的已知轉(zhuǎn)換extern char *gets (char *__s) __wur __attribute_deprecated__;
所以現(xiàn)在我們得到了 cout << 的預(yù)期錯(cuò)誤.FirstFactorial(gets(stdin));
我檢查了一個(gè)宏,因?yàn)?#undef gets
似乎什么都不做,所以它看起來不是一個(gè)宏.
但是
std::integral_constantn;
它編譯.?/p>
但是
std::integral_constantn;//行std::integral_constantn2;//錯(cuò)誤 wtf??
在 n2
行沒有出現(xiàn)預(yù)期的錯(cuò)誤.
再說一次,幾乎對(duì) main
的任何修改都會(huì)使 cout <<FirstFactorial(gets(stdin));
吐出預(yù)期的錯(cuò)誤.
此外,stdin
實(shí)際上似乎是空的.
所以我只能得出結(jié)論并推測他們有一個(gè)小程序可以解析源代碼并嘗試(很差)在將 gets(stdin)
替換為測試用例輸入值之前實(shí)際將其輸入編譯器.如果有人有更好的理論或?qū)嶋H知道他們在做什么,請分享!
這顯然是一種非常糟糕的做法.在研究這個(gè)時(shí),我發(fā)現(xiàn)這里至少有一個(gè)問題(example) 關(guān)于這一點(diǎn),因?yàn)槿藗儾恢烙幸粋€(gè)網(wǎng)站在那里做這件事,他們的答案是不要使用 gets
而是使用 ...".這確實(shí)是一個(gè)很好的建議,但只會(huì)讓 OP 更加困惑,因?yàn)槿魏螐?stdin 進(jìn)行有效讀取的嘗試都將在此站點(diǎn)上失敗.
TLDR
gets(stdin)
是無效的 C++.這是這個(gè)特定網(wǎng)站使用的噱頭(我不知道是什么原因).如果你想繼續(xù)在網(wǎng)站上提交(我既不認(rèn)可也不不認(rèn)可它)你必須使用這個(gè)結(jié)構(gòu),否則就沒有意義,但要注意它是脆弱的.幾乎對(duì) main
的任何修改都會(huì)拋出錯(cuò)誤.在本站之外使用正常的輸入閱讀方法.
Coderbyte is an online coding challenge site (I found it just 2 minutes ago).
The first C++ challenge you are greeted with has a C++ skeleton you need to modify:
#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; }
If you are little familiar with C++ the first thing* that pops in your eyes is:
int FirstFactorial(int num);
cout << FirstFactorial(gets(stdin));
So, ok, the code calls gets
which is deprecated since C++11 and removed since C++14 which is bad in itself.
But then I realize: gets
is of type char*(char*)
. So it shouldn't accept a FILE*
parameter and the result shouldn't be usable in the place of an int
parameter, but ... not only it compiles without any warnings or errors, but it runs and actually passes the correct input value to FirstFactorial
.
Outside of this particular site, the code doesn't compile (as expected), so what is going on here?
*Actually the first one is using namespace std
but that is irrelevant to my issue here.
I am intrigued. So, time to put the investigation goggles on and since I don't have access to the compiler or compilation flags I need to get inventive. Also because nothing about this code makes sense it's not a bad idea question every assumption.
First let's check the actual type of gets
. I have a little trick for that:
template <class> struct Name;
int main() {
Name<decltype(gets)> n;
// keep this function call here
cout << FirstFactorial(gets(stdin));
return 0;
}
And that looks ... normal:
/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
is marked as deprecated and has the signature char *(char *)
. But then how is FirstFactorial(gets(stdin));
compiling?
Let's try something else:
int main() {
Name<decltype(gets(stdin))> n;
// keep this function call here
cout << FirstFactorial(gets(stdin));
return 0;
}
Which gives us:
/tmp/286775780/Main.cpp:15:21: error: implicit instantiation of undefined template 'Name<int>' Name<decltype(8)> n; ^
Finally we are getting something: decltype(8)
. So the entire gets(stdin)
was textually replaced with the input (8
).
And the things get weirder. The compiler error continues:
/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__;
So now we get the expected error for cout << FirstFactorial(gets(stdin));
I checked for a macro and since #undef gets
seems to do nothing it looks like it isn't a macro.
But
std::integral_constant<int, gets(stdin)> n;
It compiles.
But
std::integral_constant<int, gets(stdin)> n; // OK
std::integral_constant<int, gets(stdin)> n2; // ERROR wtf??
Doesn't with the expected error at the n2
line.
And again, almost any modification to main
makes the line cout << FirstFactorial(gets(stdin));
spit out the expected error.
Moreover the stdin
actually seems to be empty.
So I can only conclude and speculate they have a little program that parses the source and tries (poorly) to replace gets(stdin)
with the test case input value before actually feeding it into the compiler. If anybody has a better theory or actually knows what they are doing please share!
This is obviously a very bad practice. While researching this I found there is at least a question here (example) about this and because people have no idea that there is a site out there who does this their answer is "don't use gets
use ... instead" which is indeed a good advice but only confuses the OP more since any attempt at a valid read from stdin will fail on this site.
TLDR
gets(stdin)
is invalid C++. It's a gimmick this particular site uses (for what reasons I cannot figure out). If you want to continue to submit on the site (I am neither endorsing it neither not endorsing it) you have to use this construct that otherwise would not make sense, but be aware that it is brittle. Almost any modifications to main
will spit out an error. Outside of this site use normal input reading methods.
這篇關(guān)于站點(diǎn) coderbyte 上的“gets(stdin)"是怎么回事?的文章就介紹到這了,希望我們推薦的答案對(duì)大家有所幫助,也希望大家多多支持html5模板網(wǎng)!