[解決済み] サイトcoderbyteの'gets(stdin)'はどうなっているのでしょうか?
質問
Coderbyteはオンラインコーディングチャレンジサイトです(私は2分前に見つけました)。
最初の C++ の課題 には、修正する必要のある C++ のスケルトンがあります。
#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));
ということで、よし、このコードでは
gets
を呼び出しますが、これは C++11 から非推奨となり、C++14 からは削除されたので、それ自体は悪いことです。
しかし、そこで気がついた。
gets
は
char*(char*)
. ですから
FILE*
パラメータを受け入れてはいけませんし、その結果は
int
パラメータの代わりに使えるはずがないのですが、、、 警告やエラーなしにコンパイルされるだけでなく、実行され、実際に正しい入力値が
FirstFactorial
.
この特定のサイト以外では、コードは(予想通り)コンパイルされませんが、ここで何が起こっているのでしょうか?
*実は1つ目は
using namespace std
になっていますが、それはここでの私の問題とは無関係です。
どのように解決するには?
私は興味をそそられました。そこで、調査用のゴーグルをつける時が来ました。私はコンパイラやコンパイルフラグにアクセスできないので、工夫をする必要があります。また、このコードについては何も意味をなさないので、すべての仮定を疑うのは悪い考えではないでしょう。
最初に、実際の
gets
. そのためのちょっとしたトリックがあります。
template <class> struct Name;
int main() {
Name<decltype(gets)> n;
// keep this function call here
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)
をテストケースの入力値に置き換えてから、実際にコンパイラーに送り込んでいるのではないかと推測しています。誰かがより良い理論を持っているか、実際に彼らが何をしているかを知っているならば、共有してください。
これは明らかに非常に悪い習慣です。これを研究している間、私は少なくともここに質問があることを発見しました (
例
を使わないでください。
gets
これは確かに良いアドバイスですが、このサイトでは標準入力から正しく読み込もうとすると失敗するので、OPをさらに混乱させるだけです。
TLDR
gets(stdin)
は無効なC++です。これは、この特定のサイトが使用しているギミックです (どういう理由でそうなっているのか、私にはわかりません)。もしあなたがこのサイトで投稿を続けたいなら(私はそれを支持するわけでも支持しないわけでもありません)、さもなければ意味をなさないこの構造を使わなければなりませんが、これはもろいということに注意してください。ほとんどすべての
main
を変更すると、エラーが発生します。このサイト以外では、通常の入力読み取り方法を使用してください。
関連
-
[解決済み】構造体のベクター初期化について
-
[解決済み】ファイルから整数を読み込んで配列に格納する C++ 【クローズド
-
[解決済み] 解決済み] `pthread_create' への未定義の参照 [重複] [重複
-
[解決済み] explicit キーワードの意味は?
-
[解決済み] ルール・オブ・スリーとは?
-
[解決済み] コピーアンドスワップ慣用句とは?
-
[解決済み] C++11では、標準化されたメモリモデルが導入されました。その意味するところは?そして、C++プログラミングにどのような影響を与えるのでしょうか?
-
[解決済み] C++でextern "C "を使用した場合の効果は?
-
[解決済み] const int*、const int * const、int const *の違いは何ですか?
-
[解決済み】C/C++の"-->"演算子とは何ですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] テスト
-
[解決済み】getline()が何らかの入力の後に使用されると動作しない 【重複あり
-
[解決済み】Visual Studio 2015で「非標準の構文。'&'を使用してメンバーへのポインターを作成します」エラー
-
[解決済み] 非常に基本的なC++プログラムの問題 - バイナリ式への無効なオペランド
-
[解決済み】C++プログラムでのコンソールの一時停止
-
[解決済み】Visual C++で "Debug Assertion failed "の原因となる行を見つける。
-
[解決済み】リンカーエラーです。"リンカ入力ファイルはリンクが行われていないため未使用"、そのファイル内の関数への未定義参照
-
[解決済み】C++の余分な資格エラー
-
[解決済み】VC++の致命的なエラーLNK1168:書き込みのためにfilename.exeを開くことができません。
-
[解決済み】警告 - 符号付き整数式と符号なし整数式の比較