main () 메서드는 C에서 어떻게 작동합니까? //Code } 또는 명령

주요 방법을 작성하는 데 두 가지 다른 서명이 있음을 알고 있습니다.

int main()
{
   //Code
}

또는 명령 줄 인수를 처리하기 위해 다음과 같이 작성합니다.

int main(int argc, char * argv[])
{
   //code
}

에서 C++우리가하는 방법을 오버로드 만에 할 수 있습니다 알고 C어떻게 컴파일러는이 두 가지 서로 다른 서명을 어떻게 처리합니까 main기능을?



답변

C 언어의 일부 기능은 방금 작동하는 해킹으로 시작되었습니다.

기본 및 가변 길이 인수 목록에 대한 다중 서명은 이러한 기능 중 하나입니다.

프로그래머는 함수에 추가 인수를 전달할 수 있으며 주어진 컴파일러에서 나쁜 일이 발생하지 않는다는 것을 알았습니다.

호출 규칙이 다음과 같은 경우입니다.

  1. 호출 함수는 인수를 정리합니다.
  2. 가장 왼쪽의 인수는 스택의 맨 위 또는 스택 프레임의 기본에 더 가깝기 때문에 가짜 인수가 주소 지정을 무효화하지 않습니다.

이러한 규칙을 따르는 호출 규칙 중 하나는 호출자가 인수를 팝하고 오른쪽에서 왼쪽으로 푸시되는 스택 기반 매개 변수 전달입니다.

 ;; pseudo-assembly-language
 ;; main(argc, argv, envp); call

 push envp  ;; rightmost argument
 push argv  ;;
 push argc  ;; leftmost argument ends up on top of stack

 call main

 pop        ;; caller cleans up
 pop
 pop

이러한 유형의 호출 규칙이 적용되는 컴파일러에서는 두 가지 유형 main또는 추가 유형 을 지원하기 위해 특별히 수행 할 필요가 없습니다 . main인수가없는 함수일 수 있습니다.이 경우 스택에 푸시 된 항목을 알 수 없습니다. 두 인수의 함수 인 경우 argcargv두 개의 최상위 스택 항목을 찾습니다 . 환경 포인터 (공통 확장)가있는 플랫폼 별 3 개 인수 변형 인 경우에도 작동합니다. 스택 맨 위에서 세 번째 요소로 세 번째 인수를 찾습니다.

따라서 고정 호출은 모든 경우에 작동하므로 단일 고정 시작 모듈을 프로그램에 연결할 수 있습니다. 해당 모듈은 다음과 유사한 함수로 C로 작성 될 수 있습니다.

/* I'm adding envp to show that even a popular platform-specific variant
   can be handled. */
extern int main(int argc, char **argv, char **envp);

void __start(void)
{
  /* This is the real startup function for the executable.
     It performs a bunch of library initialization. */

  /* ... */

  /* And then: */
  exit(main(argc_from_somewhere, argv_from_somewhere, envp_from_somewhere));
}

즉,이 시작 모듈은 항상 3 인수 main을 호출합니다. main이 인수를 사용하지 않거나 만 사용 int, char **하는 경우 호출 규칙으로 인해 인수가 필요하지 않을뿐만 아니라 정상적으로 작동합니다.

프로그램에서 이런 종류의 일을한다면 이식이 불가능하고 ISO C에서 정의되지 않은 동작으로 간주됩니다. 한 가지 방식으로 함수를 선언하고 호출하고 다른 방식으로 정의하는 것입니다. 그러나 컴파일러의 시작 트릭은 이식 가능할 필요가 없습니다. 휴대용 프로그램에 대한 규칙을 따르지 않습니다.

그러나 호출 규칙이 이러한 방식으로 작동 할 수 없다고 가정합니다. 이 경우 컴파일러는 main특별히 처리해야 합니다. main함수를 컴파일하고 있음을 발견 하면 세 개의 인수 호출과 호환되는 코드를 생성 할 수 있습니다.

즉, 다음과 같이 작성합니다.

int main(void)
{
   /* ... */
}

그러나 컴파일러가 그것을 볼 때 본질적으로 코드 변환을 수행하여 컴파일하는 함수가 다음과 같이 보입니다.

int main(int __argc_ignore, char **__argv_ignore, char **__envp_ignore)
{
   /* ... */
}

이름 __argc_ignore이 문자 그대로 존재하지 않는다는 점을 제외하면 . 이러한 이름은 범위에 도입되지 않으며 사용되지 않은 인수에 대한 경고도 없습니다. 코드 변환은 컴파일러가 세 개의 인수를 정리해야한다는 것을 알고있는 올바른 연결로 코드를 내보내도록합니다.

또 다른 구현 전략은 컴파일러 또는 링커가 __start함수 (또는 호출되는 모든 항목) 를 사용자 지정 생성 하거나, 미리 컴파일 된 여러 대안 중에서 하나를 선택하는 것입니다. 지원되는 형식 중 어느 main것이 사용 되는지에 대한 정보를 개체 파일에 저장할 수 있습니다 . 링커는이 정보를보고 main프로그램 정의와 호환되는 호출이 포함 된 시작 모듈의 올바른 버전을 선택할 수 있습니다 . C 구현에는 일반적으로 지원되는 형식 main이 적으므로이 접근 방식이 가능합니다.

C99 언어 용 컴파일러 main는 함수가 return명령문 없이 종료 되면 동작이 return 0실행 된 것처럼 동작 하는 해킹을 지원 하기 위해 항상 어느 정도 특별히 처리해야합니다 . 이것은 다시 코드 변환으로 처리 할 수 ​​있습니다. 컴파일러 main는 호출 된 함수 가 컴파일되고 있음을 인식합니다 . 그런 다음 신체 끝 부분에 잠재적으로 도달 할 수 있는지 여부를 확인합니다. 그렇다면return 0;


답변

과부하가 없습니다 mainC ++에서도 . 주 기능은 프로그램의 진입 점이며 단일 정의 만 존재해야합니다.

표준 C 용

호스팅 된 환경 (일반적인 환경)의 경우 C99 표준은 다음과 같이 말합니다.

5.1.2.2.1 프로그램 시작

프로그램 시작시 호출되는 함수의 이름은 main. 구현은이 함수에 대한 프로토 타입을 선언하지 않습니다. 반환 유형 int과 매개 변수없이 정의되어야합니다 .

int main(void) { /* ... */ }

또는 두 개의 매개 변수를 사용합니다 (여기에서 argc및 로 지칭됩니다. argv이름이 선언 된 함수에 로컬이기 때문에 모든 이름을 사용할 수 있음).

int main(int argc, char *argv[]) { /* ... */ }

또는 동등한 것; 9) 또는 다른 구현 정의 방식으로.

9) 따라서으로 int정의 된 typedef 이름으로 대체 int되거나의 유형이 argv로 작성 될 수 있습니다 char **argv.

표준 C ++의 경우 :

3.6.1 주요 기능 [basic.start.main]

1 프로그램은 프로그램의 지정된 시작 인 main이라는 전역 기능을 포함해야합니다. […]

2 구현시 주요 기능을 미리 정의 해서는 안됩니다 . 이 기능은 과부하되지 않아야합니다 . 반환 유형은 int 유형이어야하지만 그렇지 않으면 유형이 구현 정의됩니다. 모든 구현은 main에 대한 다음 정의를 모두 허용해야합니다.

int main() { /* ... */ }

int main(int argc, char* argv[]) { /* ... */ }

C ++ 표준은 “[주 함수]가 int 유형의 반환 유형을 가져야하지만 그렇지 않으면 해당 유형이 구현 정의 됨”이라고 명시 적으로 명시하고 C 표준과 동일한 두 개의 서명이 필요합니다.

A의 호스팅 환경 (또한 C 라이브러리를 지원하는 AC 환경) – 운영 체제를 호출합니다 main.

A의 호스트되지 않은 환경 (임베디드 애플리케이션을위한 하나) 당신은 항상 전처리 지침 등을 이용하여 프로그램의 진입 점 (또는 종료)를 변경할 수 있습니다

#pragma startup [priority]
#pragma exit [priority]

우선 순위는 선택적 정수입니다.

Pragma 시작은 기본 (우선 순위) 전에 함수를 실행하고 pragma 종료는 기본 함수 다음에 함수를 실행합니다. 하나 이상의 시작 지시문이있는 경우 우선 순위는 어느 것이 먼저 실행될 것인지 결정합니다.


답변

과부하가 필요하지 않습니다. 예, 두 가지 버전이 있지만 한 번에 하나만 사용할 수 있습니다.


답변

이것은 C 및 C ++ 언어의 이상한 비대칭 및 특수 규칙 중 하나입니다.

제 생각에는 그것은 역사적인 이유만으로 존재하며 그 뒤에 진정한 심각한 논리는 없습니다. 주 main(예를 들어, 다른 이유도 특별 mainC ++로 재귀 할 수 없으며 그 주소와 마지막을 생략 할 수 있습니다 ++ C99 / C에 걸릴 수 없습니다return 문을).

또한 C ++에서도 오버로드가 아닙니다. 프로그램에 첫 번째 형식이 있거나 두 번째 형식이 있습니다. 둘 다 가질 수는 없습니다.


답변

특이한 점은 여러 가지 방법으로 정의 main할 수 있다는 것이 아니라 두 가지 다른 방법 중 하나로 정의 할 수 있다는 것 입니다.

main사용자 정의 함수입니다. 구현은 프로토 타입을 선언하지 않습니다.

foo또는에 대해서도 마찬가지 bar이지만 원하는 방식으로 해당 이름으로 함수를 정의 할 수 있습니다.

차이점은 main자체 코드가 아니라 구현 (런타임 환경)에 의해 호출 된다는 것 입니다. 구현은 일반적인 C 함수 호출 의미 체계에 국한되지 않으므로 몇 가지 변형을 처리 할 수 ​​있습니다 (그리고 반드시 처리해야합니다).하지만 무한히 많은 가능성을 처리 할 필요는 없습니다. 이 int main(int argc, char *argv[])양식은 명령 줄 인수를 허용 int main(void)하며 C 또는int main() C ++에서는 명령 줄 인수를 처리 할 필요가없는 간단한 프로그램에 편리합니다.

컴파일러가이를 처리하는 방법은 구현에 따라 다릅니다. 대부분의 시스템에는 두 형식이 효과적으로 호환되도록하는 호출 규칙이있을 수 있으며 main매개 변수없이 정의 된에 전달 된 인수 는 조용히 무시됩니다. 그렇지 않다면 컴파일러 나 링커가 main특별히 처리하는 것이 어렵지 않을 것 입니다. 시스템 에서 어떻게 작동하는지 궁금하다면 몇 가지 어셈블리 목록을 볼 수 있습니다.

그리고 C와 C ++의 많은 것들과 마찬가지로 세부 사항은 대부분 언어 디자이너와 그 전임자들이 내린 역사와 임의의 결정의 결과입니다.

C와 C ++는 모두 다른 구현 정의 정의를 허용 main하지만이를 사용하는 좋은 이유는 거의 없습니다. 그리고 독립 구현 (예 : OS가없는 임베디드 시스템)의 경우 프로그램 진입 점은 구현에 따라 정의되며 반드시 main.


답변

main링커에 의해 결정 시작 주소 단지 이름 main기본 이름입니다. 프로그램의 모든 함수 이름은 함수가 시작되는 시작 주소입니다.

함수 인수는 스택에서 푸시 / 팝핑되므로 함수에 지정된 인수가없는 경우 스택에서 푸시 / 팝핑되는 인수가 없습니다. 이것이 main이 인수를 사용하거나 사용하지 않고 작동하는 방법입니다.


답변

음, 동일한 함수 main ()의 두 가지 다른 서명은 원할 때만 그림으로 표시됩니다. 따라서 프로그램이 실제 코드를 처리하기 전에 데이터가 필요한 경우 다음을 사용하여 전달할 수 있습니다.

    int main(int argc, char * argv[])
    {
       //code
    }

여기서 변수 argc는 전달 된 데이터의 개수를 저장하고 argv는 콘솔에서 전달 된 값을 가리키는 char에 대한 포인터 배열입니다. 그렇지 않으면 항상 함께가는 것이 좋습니다

    int main()
    {
       //Code
    }

그러나 어떤 경우에도 프로그램에는 하나의 main () 만있을 수 있습니다. 프로그램에서 실행을 시작하는 유일한 지점이므로 둘 이상일 수 없습니다. (그 가치가 있기를 바랍니다)