2009-05-21 3 views
209

나는 다음 main() 메소드의 모든 것을 내 C의 ++ 응용 프로그램을 실행하면 OK입니다 :C++에서 _tmain()과 main()의 차이점은 무엇입니까?

int main(int argc, char *argv[]) 
{ 
    cout << "There are " << argc << " arguments:" << endl; 

    // Loop through each argument and print its number and value 
    for (int i=0; i<argc; i++) 
     cout << i << " " << argv[i] << endl; 

    return 0; 
} 

내가 기대 내 인수가 인쇄되는 것을 얻을. 그러나

, 내가 _tmain 사용하는 경우 :

int _tmain(int argc, char *argv[]) 
{ 
    cout << "There are " << argc << " arguments:" << endl; 

    // Loop through each argument and print its number and value 
    for (int i=0; i<argc; i++) 
     cout << i << " " << argv[i] << endl; 

    return 0; 
} 

그냥 각 인수의 첫 번째 문자를 표시합니다.

이 문제의 원인은 무엇입니까?

답변

322

_tmain는 C++에 없습니다. main 않습니다.

_tmain은 Microsoft의 확장 프로그램입니다.

main은 C++ 표준에 따라 프로그램의 진입 점입니다. 그것은이 두 서명 중 하나가 있습니다 Microsoft는이와 함께 두 번째 서명을 대체하는 wmain 추가했다

int main(); 
int main(int argc, char* argv[]); 

: 다음

int wmain(int argc, wchar_t* argv[]); 

와, (UTF-쉽게 유니 코드 사이를 전환 할 수 있도록 16) 및 멀티 바이트 문자 세트의 경우 _tmain을 정의했으며, 유니 코드를 사용하는 경우 wmain으로 컴파일하고 그렇지 않은 경우 main으로 컴파일합니다.

질문의 두 번째 부분은 퍼즐의 첫 번째 부분은 주요 기능이 잘못되었다는 것입니다. wmainwchar_t 인수를 취해야하며 char이 아닐 것입니다. 컴파일러가 main 함수에 대해 이것을 시행하지 않기 때문에 main 함수에 wchar_t 문자열 배열이 전달되며이 문자열을 char 문자열로 해석하는 프로그램이 생성됩니다.

유니 코드가 사용 가능할 때 Windows에서 사용하는 문자 세트 인 UTF-16에서 모든 ASCII 문자는 바이트 값 쌍 \0 다음에 ASCII 값으로 표시됩니다.

x86 CPU가 리틀 엔디안이므로 이러한 바이트의 순서가 바뀌어 ASCII 값이 먼저오고 그 다음에 널 바이트가옵니다.

그리고 char 문자열에서 문자열은 일반적으로 어떻게 종료됩니까? 네, null 바이트. 따라서 여러분의 프로그램은 각각 1 바이트 길이의 문자열을 볼 수 있습니다.

  • 가 명시 적으로 (유니 코드를 사용 wmain 전화 및 문자 관련 인수를 모든 Windows API 함수에 대한 함수의 -W 버전을 호출

    는 일반적으로, 당신은 윈도우 프로그래밍을하는 세 가지 옵션이 있습니다.CreateWindow 대신 CreateWindowW를 호출하십시오. 그리고 char을 사용하는 대신 wchar_t 등을 사용하십시오.

  • 유니 코드를 명시 적으로 비활성화하십시오. main 및 CreateWindowA를 호출하고 문자열에 char을 사용하십시오.
  • 둘 다 허용하십시오. (main/_tmain 및 CreateWindowA/CreateWindowW로 해석되는 _tmain 및 CreateWindow 호출) char/wchar_t 대신 TCHAR을 사용하십시오.

동일 WINDOWS.H에 의해 정의 된 문자열 유형에 적용 : LPCTSTR은 LPCSTR 또는 LPCWSTR 중 하나를 해결하고, char 또는 wchar_t를 포함되어 다른 모든 유형 들어, -T- 버전은 항상 사용할 수있는 존재 대신.

이 모든 내용은 Microsoft에서만 적용됩니다. TCHAR은 표준 C++ 유형이 아니며, windows.h에 정의 된 매크로입니다. wmain 및 _tmain은 Microsoft에서만 정의됩니다.

+6

그들이 tcout도 제공하는지 궁금하네요? 그래서 사람은 단지 tcout << argv [n];을 할 수 있습니다. 그리고 그것은 Ansi와 Unicode 모드에서 wcout으로 해석합니다. 나는 그것이이 상황에서 그를 위해 유용 할 수 있다고 생각한다. +1 물론, 좋은 대답 :) –

+1

UNICODE를 사용하지 못하게하는 데 어떤 단점이 있습니까? – joshcomley

+0

@Johannes Schaub - litb : AFAIK, 그들은 tcout을 제공하지 않습니다 (비록 그들이 cout과 wcout를 제공하더라도). Visual C++ 2003에서는 TCHAR을 사용하고자하는 다른 모든 STL 관련 심볼을 정의 및 정의하거나 typedef를 정의해야했습니다. Visual C++ 2008 또는 2010에 대해서는 잘 모릅니다. – paercebal

10

_T 규약은 프로그램이 응용 프로그램 용으로 정의 된 문자 집합 (유니 코드, ASCII, MBCS 등)을 사용해야 함을 나타 내기 위해 사용됩니다. 문자열을 _T()로 묶으면 올바른 형식으로 저장됩니다.

cout << _T("There are ") << argc << _T(" arguments:") << endl; 
+0

실제로,이 방법 afaik를 권장합니다. 응용 프로그램을 유니 코드 인식으로 만들면 모든 문자열 조작 함수의 _t 버전을 사용하여 호출합니다. –

+1

@ Deep-B : 그리고 Windows의 경우,이 **는 ** 응용 프로그램을 유니 코드로 준비시키는 방법입니다 (이전에 char에 기반한 경우 유니 코드 준비 상태를 선호합니다). 애플리케이션이'wchar_t'를 직접 사용한다면 애플리케이션 **은 ** unicode입니다. – paercebal

+5

그런데 UNICODE에서 컴파일하려고하면 코드가 wcout이되어야하는 char 기반 cout 내부의 출력 wchar_t로 컴파일되지 않습니다. "tcout"을 정의하는 예에 대한 Michael J의 대답을 참조하십시오 ... – paercebal

34

_tmain은 유니 코드 또는 ASCII로 컴파일할지 여부에 따라 재정의되는 매크로입니다. Microsoft 확장이며 다른 컴파일러에서 작동하지 않을 수도 있습니다. 매크로 유니 코드가 정의되어있는 경우

올바른 선언은 그렇지

int wmain(int argc, wchar_t *argv[]) 

로 확장하는,

int _tmain(int argc, _TCHAR *argv[]) 

입니다 그것은

int main(int argc, char *argv[]) 

귀하의 정의는 약간 간다로 확장 각 유니 코드 및 (유니 코드가 정의 된 경우)

으로 확장됩니다.
int wmain(int argc, char *argv[]) 

이는 보통 오류입니다.

std :: cout은 ASCII 문자로 작동합니다. 와이드 문자를 사용하는 경우 std :: wcout이 필요합니다.

#include <iostream> 
#include <tchar.h> 

#if defined(UNICODE) 
    #define _tcout std::wcout 
#else 
    #define _tcout std::cout 
#endif 

int _tmain(int argc, _TCHAR *argv[]) 
{ 
    _tcout << _T("There are ") << argc << _T(" arguments:") << std::endl; 

    // Loop through each argument and print its number and value 
    for (int i=0; i<argc; i++) 
     _tcout << i << _T(" ") << argv[i] << std::endl; 

    return 0; 
} 

같은 것을 시도하거나 당신은 단지 넓거나 좁은 문자를 사용할지 여부를 미리 결정할 수있다. :-)

12 년 11 월 2013 업데이트 :

은 전통적인 "TCHAR"변경된 최신 패션 것 같다 "_TCHAR"로 설정합니다. 둘 다 잘 작동합니다.

최종 업데이트

+1

+1'_tmain'은'char'가 아닌'TCHAR'을 사용합니다. – user7116

+1

* "Microsoft 확장이며 다른 컴파일러에서는 작동하지 않습니다."* [RAD Studio와 관련이 없습니다] (http://docwiki.embarcadero.com/RADStudio/XE3/en/TCHAR_Mapping) –

+0

@ b1naryatr0phy - 머리카락을 나눌 때, 링크하는 도구는 "TCHAR"대신 "_TCHAR"을 사용하므로 호환되지 않습니다 (내 성명을 위조하지만). 그러나 나는 "이것은 Microsoft의 확장이며 다른 컴파일러에서 작동하지 않을 것"이라고 말해야했습니다. " 나는 원본을 고칠 것이다. –

5

확인, 문제는 상당히 잘 대답 한 것, 유니 코드 오버로드는 두 번째 매개 변수로 와이드 문자 배열을해야합니다. 따라서 명령 줄 매개 변수가 "Hello" 인 경우 "H\0e\0l\0l\0o\0\0\0"으로 끝나고 프로그램은 'H' 만 인쇄하기 전에 Null 종결 자라고 판단합니다.

이제 컴파일 및 링크까지하는 이유가 궁금 할 것입니다.

함수에 과부하를 정의 할 수 있으므로 컴파일됩니다.

연결은 약간 더 복잡한 문제입니다. C에서는 꾸며진 기호 정보가 없으므로 main이라는 함수 만 찾습니다. argc와 argv는 아마 당신의 함수가 그것들을 무시할지라도 당신의 함수가 그 시그니처로 정의된다고하더라도 call-stack 매개 변수로서 항상 존재할 것이다.

C++에 데코 레이팅 된 심볼이 있더라도 각 심볼을 순서대로 찾는 영리한 링커가 아니라 C-linkage를 main으로 사용합니다. 그래서 그것은 wmain을 찾았고 int wmain(int, wchar_t*[]) 버전 인 경우 호출 스택에 매개 변수를 넣습니다.

+0

좋아, 그래서 난 문제가 왜 내 코드를 Windows 와이드 년 동안 포팅하고 처음으로 나는 이것이 일어나는 이유를 이해합니다. 자, 내 모든 명성을 가져라! 하하 – Leonel

0

이 템플릿을 약간의 노력을 기울이면 모든 개체 목록을 사용하여 작업 할 수 있습니다.

#include <iostream> 
#include <string> 
#include <vector> 

char non_repeating_char(std::string str){ 
    while(str.size() >= 2){ 
     std::vector<size_t> rmlist; 
     for(size_t i = 1; i < str.size(); i++){   
      if(str[0] == str[i]) { 
       rmlist.push_back(i); 
      }  
     }   

     if(rmlist.size()){    
      size_t s = 0; // Need for terator position adjustment 
      str.erase(str.begin() + 0); 
      ++s; 
      for (size_t j : rmlist){ 
       str.erase(str.begin() + (j-s));     
       ++s; 
      } 
     continue; 
     } 
     return str[0]; 
    } 
    if(str.size() == 1) return str[0]; 
    else return -1; 
} 

int main(int argc, char ** args) 
{ 
    std::string test = "FabaccdbefafFG"; 
    test = args[1]; 
    char non_repeating = non_repeating_char(test); 
    Std::cout << non_repeating << '\n'; 
} 
관련 문제