Jestem zaintrygowany. Czas więc założyć gogle śledcze, a ponieważ nie mam dostępu do kompilatora ani flag kompilacji, muszę się wykazać pomysłowością. Ponieważ nic w tym kodzie nie ma sensu, nie jest to zły pomysł, kwestionuj każde założenie.
Najpierw sprawdźmy rzeczywisty typ gets
. Mam na to małą sztuczkę:
template <class> struct Name;
int main() {
Name<decltype(gets)> n;
// keep this function call here
cout << FirstFactorial(gets(stdin));
return 0;
}
A to wygląda ... normalnie:
/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
jest oznaczony jako przestarzały i ma podpis char *(char *)
. Ale jak wygląda FirstFactorial(gets(stdin));
kompilacja?
Spróbujmy czegoś innego:
int main() {
Name<decltype(gets(stdin))> n;
// keep this function call here
cout << FirstFactorial(gets(stdin));
return 0;
}
Co daje nam:
/tmp/286775780/Main.cpp:15:21: error: implicit instantiation of undefined template 'Name<int>'
Name<decltype(8)> n;
^
Wreszcie jesteśmy coraz coś: decltype(8)
. Więc całość gets(stdin)
została zastąpiona tekstowo przez input ( 8
).
I rzeczy stają się dziwniejsze. Błąd kompilatora jest kontynuowany:
/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__;
Więc teraz otrzymujemy oczekiwany błąd dla cout << FirstFactorial(gets(stdin));
Sprawdziłem, czy nie ma makra, a ponieważ #undef gets
wydaje się nic nie robić, wygląda na to, że nie jest to makro.
Ale
std::integral_constant<int, gets(stdin)> n;
Kompiluje się.
Ale
std::integral_constant<int, gets(stdin)> n; // OK
std::integral_constant<int, gets(stdin)> n2; // ERROR wtf??
Nie z oczekiwanym błędem na n2
linii.
I znowu, prawie każda modyfikacja main
powoduje, że linia cout << FirstFactorial(gets(stdin));
wypluwa oczekiwany błąd.
Co więcej, stdin
faktycznie wydaje się być pusty.
Mogę więc tylko wywnioskować i spekulować, że mają mały program, który analizuje źródło i próbuje (słabo) zastąpić gets(stdin)
go wartością wejściową przypadku testowego, zanim faktycznie wprowadzi go do kompilatora. Jeśli ktoś ma lepszą teorię lub naprawdę wie, co robi, podziel się nim!
To oczywiście bardzo zła praktyka. Podczas badania tego stwierdziłem, że jest tu przynajmniej pytanie ( przykład ) na ten temat, a ponieważ ludzie nie mają pojęcia, że istnieje strona, która to robi, ich odpowiedź brzmi "nie gets
używaj ... zamiast tego", co rzeczywiście jest dobra rada, ale tylko bardziej dezorientuje OP, ponieważ każda próba prawidłowego odczytu ze standardowego wejścia zakończy się niepowodzeniem w tej witrynie.
TLDR
gets(stdin)
jest nieprawidłowy C ++. To sztuczka, której używa ta konkretna witryna (z jakich powodów nie mogę się dowiedzieć). Jeśli chcesz nadal publikować na stronie (ani nie popieram ani nie popieram), musisz użyć tej konstrukcji, która w przeciwnym razie nie miałaby sensu, ale pamiętaj, że jest krucha. Prawie każda modyfikacja main
spowoduje wyświetlenie błędu. Poza tą witryną używaj normalnych metod odczytu danych wejściowych.
stdin
w standardowej bibliotece jest aFILE*
, a wskaźnik do dowolnego typu jest konwertowany nachar*
, który jest typem argumentugets()
. Jednak nigdy, przenigdy nie powinieneś pisać tego rodzaju kodu poza zaciemnionym konkursem w C. Jeśli Twój kompilator w ogóle to akceptuje, dodaj więcej flag ostrzegawczych, a jeśli próbujesz naprawić bazę kodu zawierającą tę konstrukcję, zamień ostrzeżenia w błędy.