사이트 코더 바이트에서 ‘gets (stdin)’은 어떻게됩니까? cout << FirstFactorial(gets(stdin)); return 0; } 당신이 먼저

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.

이 특정 사이트 이외의 코드는 예상대로 컴파일되지 않으므로 여기에서 무슨 일이 있습니까?


* 실제로는 첫 번째 using namespace std이지만 내 문제와 관련이 없습니다.



답변

저는 Coderbyte의 창립자이며이 gets(stdin)핵 을 만든 사람입니다 .

이 게시물에 대한 의견은 그것이 찾기 및 바꾸기의 형태라는 것이 정확하므로 내가 왜 그렇게 빨리했는지 설명하겠습니다.

2012 년 경에 처음 사이트를 만든 당시에는 JavaScript 만 지원했습니다. 브라우저에서 실행되는 JavaScript에서 “입력을 읽는”방법이 없었으므로 함수가 있고 Node.js foo(input)readline()함수를 사용하여 처럼 호출했습니다 foo(readline()). 내가 어 렸고 더 잘 몰랐기 때문에 문자 그대로 readline()런타임에 입력으로 바꿨습니다. 그래서이 foo(readline())되었다 foo(2)또는 foo("hello")자바 스크립트 벌금을 근무한다.

2013/2014 년경에 더 많은 언어를 추가하고 타사 서비스를 사용하여 코드를 온라인으로 평가했지만 사용중인 서비스로 stdin / stdout을 수행하는 것은 매우 어려웠으므로 언어에 대해 동일한 어리석은 찾기 및 바꾸기를 고수했습니다. Python, Ruby 및 C ++, C # 등

오늘 빨리, 나는 내 컨테이너에서 코드를 실행하지만 사람들이 이상한 해킹에 익숙해 져서 stdin / stdout 작동 방식을 업데이트하지 않았습니다 (일부 사람들은 포럼에 게시하는 방법을 설명했습니다).

모범 사례가 아니며 새로운 언어를 배우는 사람이 이와 같은 해킹을 보는 데 도움이되지 않는다는 것을 알고 있지만 새로운 프로그래머는 입력을 전혀 걱정하지 않고 알고리즘을 작성하여 문제를 해결하는 데 집중했습니다. 문제. 몇 년 전 사이트 코딩 문제에 대한 일반적인 불만 사항 중 하나는 새로운 프로그래머가 stdin파일에서 줄 을 읽 거나 읽는 방법을 알아내는 데 많은 시간을 할애한다는 점입니다 . 따라서 새로운 코더가 Coderbyte에서이 문제를 피하기를 원했습니다.

기본 코드와 함께 전체 편집기 페이지를 곧 업데이트하고 stdin언어를 읽을 것입니다. 희망적으로 C ++ 프로그래머는 Coderbyte를 더 많이 사용하게 될 것입니다 🙂


답변

나는 흥미 롭다. 따라서 조 사용 고글을 착용 할 시간이며 컴파일러 또는 컴파일 플래그에 액세스 할 수 없으므로 독창적이어야합니다. 또한이 코드에 대한 의미가 없기 때문에 모든 가정에 대해 나쁜 생각은 아닙니다.

먼저 실제 유형을 확인합시다 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때문에 실제로는 “사용 하지 마십시오 … 대신”입니다. stdin의 유효한 읽기 시도가이 사이트에서 실패하기 때문에 좋은 조언이지만 OP를 더 혼란스럽게합니다.


TLDR

gets(stdin)유효하지 않은 C ++입니다. 이 특정 사이트가 사용하는 특수 효과입니다 (어떤 이유로 알아낼 수 없는지). 사이트에 계속 제출하려면 (나는 그것을지지하지도 않고 그것을지지하지도 않습니다) 그렇지 않으면 이해할 수없는이 구조를 사용해야하지만 부서지기 쉽습니다. 거의 모든 수정 main은 오류를 뱉어냅니다. 이 사이트 외부에서는 일반적인 입력 판독 방법을 사용하십시오.


답변

mainCoderbyte 편집기에서 다음을 추가했습니다 .

std::cout << "gets(stdin)";

신비스럽고 수수께끼 같은 스 니펫 gets(stdin)이 문자열 리터럴 안에 나타납니다. 이것은 아마도 아무것도에 의해조차 처리기를 변형하고,해서는 안 모든 C ++ 프로그래머가이 코드는 정확한 문자열을 인쇄하는 기대한다 gets(stdin)표준 출력으로. 그럼에도 불구하고 우리는 코더 바이트에서 컴파일되고 실행될 때 다음과 같은 결과를 볼 수 있습니다 :

8

8편집기 아래의 편리한 ‘입력’필드에서 바로 값 을 가져옵니다.

이것으로부터,이 온라인 편집기는 소스 코드에 대한 맹검 찾기 및 바꾸기 작업을 수행 gets(stdin)하고 사용자의 ‘입력’으로 대체 된 것으로 보입니다 . 나는 개인적으로 이것을 부주의 한 전 처리기 매크로보다 나쁜 언어의 오용이라고 부릅니다.

온라인 코딩 챌린지 웹 사이트의 맥락에서 나는 이것이 기존의 비표준적이고 의미가 없으며 적어도 안전하지 않은 관행 gets(stdin)을 다른 플랫폼에서 반복 할 수없는 방식으로 가르치기 때문에 걱정됩니다 .

사용 하기가 어렵고 std::cin입력을 프로그램으로 스트리밍 하는 것이 쉽지 않을 것이라고 확신합니다 .