"계속하려면 아무 키나 누르시겠습니까?"를 시뮬레이션하는 방법


87

사용자가 키보드에서 문자를 입력하면 다음 코드 줄로 이동해야하는 C ++ 프로그램을 작성하려고합니다.

내 코드는 다음과 같습니다.

char c;

cin>>c;

cout<<"Something"<<endl;

그러나 이것은 어떤 문자를 입력하고 ENTER를 누르면 다음 줄로 이동하기 때문에 작동하지 않습니다.

또는

이것을 사용하면

cin.get() or cin.get(c)

Enter 키를 누르면 다음 줄로 이동합니다.

하지만 키보드에서 눌린 키의 다음 줄로 이동하고 싶었습니다. 어떻게 할 수 있습니까?


내가 아는 한, 문제는 쉘이 ENTER 또는 EOF를 누르기를 기다린 다음 프로그램이 버퍼에있는 모든 것을 처리하도록한다는 것입니다. 더 많은 지식을 가진 사람이 실제 설명을 제공 할 수 있습니다. 하지만 처음 나타나는 것만 큼 쉽지 않다고 생각합니다.
Lucas

7
이를 처리하는 가장 쉬운 방법이자 유일한 이동식 방법은 프롬프트를 "계속하려면 아무 키나 누르십시오"에서 "계속하려면 Enter 키를 누르십시오"로 변경하는 것입니다.
rob mayoff 2012

@Lucas-xcode와 함께 Mac을 사용하고 있습니다.
itsaboutcode 2012

@Lucas : 셸이 아니라 프로그램 자체입니다.
Keith Thompson

@KeithThompson : 이것은 2 년 이상 전 일이지만 입력 대기열이 사용자 프로세스에 의해 처리되지 않고 커널 내부에서 처리된다는 점을 지적하려고했습니다.
Lucas

답변:


64

Windows의 경우 :

system("pause");

Mac 및 Linux :

system("read");

"계속하려면 아무 키나 누르십시오 ..."를 출력하고 아무 키나 누르기를 기다립니다. 그게 당신의 뜻 이었으면 좋겠어요


5
system외부 프로그램을 호출합니다. 키를 기다리기 위해 외부 프로그램을 호출 할 필요가 없습니다! 컴퓨터 앞에 앉아있을 때 다른 사람에게 전화를 걸어 컴퓨터를 켜는 것과 같습니다. 이것은 느린 해결책입니다.
GingerPlusPlus

8
사실이지만 한 줄 밖에 안됩니다! 가끔은 ... 그냥 가치가 컴퓨터에게 어떤 사이클을 절약하기위한 노력입니다
엘리엇 카메론

14
천천히 잊으십시오. PATH에서 찾은 "pause"라는 이름의 첫 번째 프로그램을 호출하고 호출 프로그램의 권한 수준을 제공합니다. 자신의 코드를 테스트하는 학생이더라도 여전히 엄청난 보안 위험이 있습니다.
Anne Quinn 2014

6
@XDfaceme-pause는 system ()이 창 실행을 요청하는 실제 프로그램입니다. 그러나 '일시 중지'라는 다른 프로그램이 있고 Windows가 해당 프로그램을 먼저 찾으면 대신 실행합니다. 나는 중요성 조금 과장된했습니다 수도 있습니다 생각하지만, 프로그램을 일시 중지 해제 / 바로 사용 cin.get () 및 일시 정지로 히트 반환에 여전히 쉽게
앤 퀸

2
나는 절대적인 팬이 아닙니다. 시스템 ( "일시 정지")은 보안 위험이며 자신의 코드를 테스트 할 때도 문제가 발생하는 상황에서도 나쁘다는 포괄적 인 진술을합니다. cin.get ()이 올바른 해결책 일 수 있지만 질문을받은 질문을 해결하지 못합니다 ... cin.get ()은 "enter"또는 "return"을 누른 후에 만 ​​응답합니다. 질문은 특히 모든 키 누름에 응답하는 것이 었습니다. system ( "pause")이 정확히 수행합니다. 우선, Visual Studio에서 디버깅 할 때 이것이 유용하다고 본 유일한 곳은 dev 클래스에 있습니다. 그래서 system ( "pause")이 작동한다고 생각합니다
Gregor

52

Windows를 사용 kbhit()하는 경우 Microsoft 런타임 라이브러리의 일부를 사용할 수 있습니다 . Linux를 사용하는 경우 다음과 kbhit같이 구현할 수 있습니다 ( source ).

#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>

int kbhit(void)
{
  struct termios oldt, newt;
  int ch;
  int oldf;

  tcgetattr(STDIN_FILENO, &oldt);
  newt = oldt;
  newt.c_lflag &= ~(ICANON | ECHO);
  tcsetattr(STDIN_FILENO, TCSANOW, &newt);
  oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
  fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);

  ch = getchar();

  tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
  fcntl(STDIN_FILENO, F_SETFL, oldf);

  if(ch != EOF)
  {
    ungetc(ch, stdin);
    return 1;
  }

  return 0;
}

업데이트 : 위의 기능은 OS X에서 작동합니다 (적어도 OS X 10.5.8-Leopard에서 작동하므로 OS X의 최신 버전에서 작동 할 것으로 예상합니다). 이 요점 은 다음 kbhit.c을 사용하여 Linux 및 OS X에서 저장 하고 컴파일 할 수 있습니다.

gcc -o kbhit kbhit.c

함께 실행할 때

./kbhit

키를 누르라는 메시지가 표시되고 키를 누르면 종료됩니다 (Enter 또는 인쇄 가능한 키에 국한되지 않음).

@Johnsyweb- "상세한 표준 답변"과 "모든 우려 사항"이 의미하는 바를 자세히 설명해주십시오. 또한 "크로스 플랫폼":이 구현을 kbhit()통해 Linux / Unix / OS X / Windows의 C ++ 프로그램에서 동일한 기능을 사용할 수 있습니다. 다른 플랫폼을 참조 할 수 있습니까?

@Johnsyweb에 대한 추가 업데이트 : C ++ 응용 프로그램은 밀폐 된 C ++ 환경에 있지 않습니다. C ++의 성공에 대한 큰 이유는 C와의 상호 운용성입니다. 모든 주류 플랫폼은 C 인터페이스로 구현됩니다 (내부 구현에서 C ++를 사용하는 경우에도). 따라서 "레거시"에 대한 이야기는 적절하지 않은 것처럼 보입니다. 게다가 우리가 단일 함수에 대해 이야기하고 있는데 왜 이것을 위해 C ++ ( "C with classes")가 필요합니까? 내가 지적했듯이 C ++로 작성하고이 기능에 쉽게 액세스 할 수 있으며 애플리케이션의 사용자는이 를 구현 하는 방법 에 관심이 없을 것입니다.


콘솔을 처리하는 표준 방법이 없다는 것은 부끄러운 일입니다. 항상 OS magick를 사용해야합니다
Vargas

1
@Johnsyweb : 감사 합니다 .하지만 귀하의 예는 C ++에 대해 저를 우울하게하는 기능을 보여줍니다. 당신의 kbhit()함수는 terminal_settings아무것도하지 않는 것처럼 보이는 줄에서 변수를 선언 하지만 모든 것을 수행합니다. 어떤 사람들은 그것이 깔끔하다고 생각할 수도 있지만 읽을 수 없을 정도로 모호하다고 생각합니다.
Vinay Sajip 2012

1
@VinaySajip : 제 구현에서는 C ++에서 가장 중요한 관용구 중 하나 인 RAII를 사용합니다 . 이 예제에서 꼭 필요한 것은 아니지만 일부 상태를 저장하고 복원하려는 경우에 들어가는 것이 좋은 습관임을 발견했습니다.
Johnsyweb

4
@Johnsyweb : 저는 RAII와 그것이 가져다주는 이점을 알고 있습니다. 저는 저 자신이 오래된 C ++ 손입니다. 내 요점은 여전히 ​​남아있다. 선언과 그것이 무대 뒤에서하는 일 사이에는 명확한 연관성이 없다. 평범한 오래된 C가 아닌 반짝이는 C ++ 관용구를 사용하고 있을지 모르지만, 제 생각에는 조명을 거의 밝히지 않고 무슨 일이 일어나고 있는지 모호하게 만드는 것이 많다는 것입니다. 이것은 개인적으로 어떤 식 으로든 당신을 향한 것이 아닙니다. 이것은 C ++를 사용하여 불필요하게 이해하기 어려운 코드를 생성하는 방법에 대한 의견 일뿐입니다. 나는 지금 내 비누 상자에서 내릴 것이다 .'nuff가 말했다.
Vinay Sajip

2
그것은 멋지고 모든 것이지만 여전히 stdin에서 이전 쓰레기를 잡습니다 :-)
Tiago

8

완전히 이식 가능한 솔루션은 없습니다.

comp.lang.c FAQ 의 질문 19.1은 Windows, Unix 계열 시스템, 심지어 MS-DOS 및 VMS를위한 솔루션으로이 문제를 깊이있게 다룹니다.

빠르고 불완전한 요약 :

  • curses라이브러리 를 사용할 수 있습니다 . call cbreak()뒤에 getch()(Windows 관련 getch()기능 과 혼동하지 마십시오 ). 참고 curses이 과잉 될 가능성이 있으므로, 일반적으로, 단말의 제어 걸린다.
  • ioctl()터미널 설정을 조작하는 데 사용할 수 있습니다 .
  • POSIX 호환 시스템에서, tcgetattr()그리고 tcsetattr()더 나은 해결책이 될 수 있습니다.
  • Unix에서는를 사용 system()하여 stty명령 을 호출 할 수 있습니다 .
  • MS-DOS에서는 getch()또는 getche().
  • VMS (현재 OpenVMS라고 함)에서는 화면 관리 ( SMG$) 루틴이 트릭을 수행 할 수 있습니다.

이러한 모든 C 솔루션은 C ++에서 똑같이 잘 작동합니다. C ++ 관련 솔루션을 모릅니다.


이러한 모든 다중 플랫폼 솔루션은 플랫폼이 무엇인지 결정하기 위해 많은 전처리 기가있는 플랫폼에 따라 올바른 작업을 수행하도록 구현 된 함수를 작성하는 사람과 함께 할 수 있습니다.
CashCow

6

이 기능을 달성하기 위해 Windows와 Linux (그리고 내가 아는 한 MacOS)에서 모두 구현 된 ncurses 라이브러리를 사용할 수 있습니다 .


글쎄, 이것은 외부 라이브러리 등을 사용할 수없는 일종의 할당이므로 "chapter context"lox에 머물러야합니다.
itsaboutcode

2
그런 다음 유일한 옵션은 지원하려는 각 OS에 필요한 기능을 구현하는 것입니다.
Kirill V. Lyadvinsky

1
ncurses는 다소 VT200 클라이언트입니다. 단순히 TTY에서 읽는 데 약간 과잉입니다.
greyfade

5

Windows에서이 짧은 프로그램은 목표를 달성합니다. getch키를 누를 때까지 콘솔을 일시 중지합니다 ( https://www.geeksforgeeks.org/difference-getchar-getch-getc-getche/ )

#include<iostream.h>
#include<conio.h>

using namespace std;

void  check()
{
    char chk; int j;
    cout<<"\n\nPress any key to continue...";
    chk=getch();
    j=chk;
    for(int i=1;i<=256;i++)
      if(i==j) break;
    clrscr();
}

void main()
{
    clrscr();
    check();
    cout<<"\n\nIt works!";
    getch();
}

getch는 표준 라이브러리의 일부가 아닙니다.


1
이 매우 간단한 프로그램입니다. 그것의 아주 쉽게 이해하기
BoldX

1
방법을 설명하십시오 getch()다른 cin.getcin>>, 문서에 어쩌면 일부 링크
user2622016

1
conio는 Windows에
앤드류 울프

4

저도 똑같은 일을하고 싶었 기 때문에 당신이 달성하려는 것을 조사했습니다. Vinay 에게 영감을 받아 저에게 맞는 글을 썼고 저는 이해합니다. 하지만 저는 전문가가 아니니 조심하세요.

Vinay가 여러분이 Mac OS X를 사용하고 있다는 것을 어떻게 알 수 있는지 모르겠습니다.하지만 대부분의 유닉스 계열 OS에서는 이와 같이 작동합니다. 리소스가 opengroup.org이므로 정말 유용합니다.

기능을 사용하기 전에 버퍼를 플러시하십시오.

#include <stdio.h>
#include <termios.h>        //termios, TCSANOW, ECHO, ICANON
#include <unistd.h>     //STDIN_FILENO


void pressKey()
{
    //the struct termios stores all kinds of flags which can manipulate the I/O Interface
    //I have an old one to save the old settings and a new 
    static struct termios oldt, newt;
    printf("Press key to continue....\n");

    //tcgetattr gets the parameters of the current terminal
    //STDIN_FILENO will tell tcgetattr that it should write the settings
    // of stdin to oldt
    tcgetattr( STDIN_FILENO, &oldt);
    //now the settings will be copied 
    newt = oldt;

    //two of the c_lflag will be turned off
    //ECHO which is responsible for displaying the input of the user in the terminal
    //ICANON is the essential one! Normally this takes care that one line at a time will be processed
    //that means it will return if it sees a "\n" or an EOF or an EOL
    newt.c_lflag &= ~(ICANON | ECHO );      

    //Those new settings will be set to STDIN
    //TCSANOW tells tcsetattr to change attributes immediately. 
    tcsetattr( STDIN_FILENO, TCSANOW, &newt);

    //now the char wil be requested
    getchar();

    //the old settings will be written back to STDIN
    tcsetattr( STDIN_FILENO, TCSANOW, &oldt);

}


int main(void)
{
  pressKey();
  printf("END\n");
  return 0;
}

O_NONBLOCK도 중요한 플래그 인 것 같지만 저에게는 아무것도 바뀌지 않았습니다.

좀 더 깊은 지식을 가진 사람들이 이것에 대해 논평하고 조언을 해주면 감사합니다.


O_NONBLOCK이 없으면 getchar () (read () 호출)가 입력 대기를 차단하므로 설정해야합니다. kbhit () 솔루션은 기다리지 않고 키를 눌렀는지 알려줍니다. 대기 루프 또는 다른 목적으로 사용할 수 있으므로보다 일반적인 솔루션입니다. O_NONBLOCK이없는 솔루션은 키를 누를 때까지 기다릴 것입니다.-이 질문은 괜찮지 만 일반적으로 덜 유용합니다.
Vinay Sajip

4

Microsoft 전용 함수 _getch를 사용할 수 있습니다 .

#include <iostream>
#include <conio.h>
// ...
// ...
// ...
cout << "Press any key to continue..." << endl;
_getch();
cout << "Something" << endl;

3

이것은 Windows 플랫폼에서 작동 합니다. 마이크로 프로세서 레지스터를 직접 사용하고 키 누름 또는 마우스 버튼을 확인하는 데 사용할 수 있습니다.

    #include<stdio.h>
    #include<conio.h>
    #include<dos.h>
    void main()
    {
     clrscr();
     union REGS in,out;
     in.h.ah=0x00;
     printf("Press any key : ");

     int86(0x16,&in,&out);
     printf("Ascii : %d\n",out.h.al);
     char ch = out.h.al;
     printf("Charcter Pressed : %c",&ch);
     printf("Scan code : %d",out.h.ah);
     getch();
    }

3

Visual Studio 2012 이하를 사용하는 getch()경우 함수를 사용하고 Visual Studio 2013 이상을 사용하는 경우 _getch(). 을 사용해야 #include <conio.h>합니다. 예:

#include <iostream>
#include <conio.h>

int main()
{
   std::cout << "Press any key to continue. . .\n";
   _getch(); //Or getch()
}

1

getchar 루틴을 사용할 수 있습니다 .

위 링크에서 :

/* getchar example : typewriter */
#include <stdio.h>

int main ()
{
  char c;
  puts ("Enter text. Include a dot ('.') in a sentence to exit:");
  do {
    c=getchar();
    putchar (c);
  } while (c != '.');
  return 0;
}

3
나는 그를 올바르게 이해한다면 이것이 OP가 요구 한 것이라고 생각하지 않습니다. getchar ()에서 읽을 수 있으려면 여전히 Enter 키를 눌러 버퍼를 채워야합니다.
Lucas

0

또한 conio.h에서 getch ()를 사용할 수 있습니다. 다음과 같이 :

...includes, defines etc
void main()
{
//operator
getch(); //now this function is waiting for any key press. When you have pressed its     just     //finish and next line of code will be called
}

따라서 UNIX에는 conio.h가 없기 때문에이 코드로 getch ()를 시뮬레이션 할 수 있습니다 (하지만이 코드는 이미 Vinary에서 작성했습니다. 실패했습니다).

#include <stdio.h>
#include <termios.h>
#include <unistd.h>

int mygetch( ) {
  struct termios oldt,
             newt;
  int            ch;
  tcgetattr( STDIN_FILENO, &oldt );
  newt = oldt;
  newt.c_lflag &= ~( ICANON | ECHO );
  tcsetattr( STDIN_FILENO, TCSANOW, &newt );
  ch = getchar();
  tcsetattr( STDIN_FILENO, TCSANOW, &oldt );
  return ch;
}

-1

지금 MSDN에서 kbhit () 함수를 찾으면 해당 함수가 더 이상 사용되지 않는다고 표시됩니다. 대신 _kbhit ()을 사용하십시오.

#include <conio.h>
int main()
{
    _kbhit();
    return 0;
}

-1
#include <iostream>
using namespace std;

int main () {
    bool boolean;
    boolean = true;

    if (boolean == true) {

        cout << "press any key to continue";
        cin >> boolean;

    }
    return 0;
}

-4

system("pause");명령을 사용하십시오 .

다른 모든 답변은 문제를 복잡하게 만듭니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.