IT

메인() 기능을 사용하지 않고 프로그램을 작성할 수 있습니까?

itgroup 2023. 8. 11. 21:43
반응형

메인() 기능을 사용하지 않고 프로그램을 작성할 수 있습니까?

저는 인터뷰에서 이 질문을 계속 받습니다.

프로그램을 사용하지 합니다.main()기능?

제 친구 중 한 명이 매크로를 사용하여 코드를 보여주었지만, 저는 이해할 수 없었습니다.

그래서 질문은 다음과 같습니다.

프로그램을 작성하고 컴파일하는 것이 정말로 가능합니까?main()?

요, 하는 경우가 할 수 .freestanding environment 커널 등)이 필요 ("mbedded environment OS ") 시작지필이경않우임은지요하점등디드베환경커널▁(▁the경우임▁need▁wherement▁etc▁os않"main() C++ 표준에 따름main()는 든프그시니다입작점에 있는 입니다.hosted environment.

다음에 따름:

C++03 표준 3.6.1기능

1 프로그램은 프로그램의 지정된 시작인 main이라는 글로벌 함수를 포함해야 합니다.주 기능을 정의하기 위해 독립 환경의 프로그램이 필요한지 여부는 구현 정의됩니다.[ 참고:독립 실행형 환경에서 시작 및 종료는 구현 정의됩니다. 시작은 정적 저장 기간이 있는 네임스페이스 범위 개체에 대한 생성자 실행을 포함하고 종료는 정적 저장 기간이 있는 개체에 대한 소멸자 실행을 포함합니다.


란?freestanding Environment무이가 입니까?Hosted Environment?
두 가지가 있습니다. C++ 두가종준있구다습니현수이류의표지준의에된정▁c▁thereations▁defined▁kinds다;니있▁are습▁the▁of▁in▁two▁standard+ing▁c▁implement▁conform+구현이준수.hosted그리고.freestanding.

A freestanding구현은 운영 체제의 이점 없이 실행되는 프로그램을 위해 설계된 것입니다.
예를 들어 OS 커널 또는 Embedded 환경은 독립적인 환경입니다.

▁a▁in▁using▁normally▁a다▁be같니에 있습니다.hosted implementation.

C++03 표준 섹션 1.4/7에서:

독립 실행형 구현은 운영 체제의 이점 없이 실행될 수 있는 구현이며 특정 언어 지원 라이브러리를 포함하는 구현 정의 라이브러리 집합을 가지고 있습니다.

더 나아가서 ,
섹션: 17.4.1.3.2 독립 실행형 인용문:

독립 실행형 구현에는 구현 정의 헤더 집합이 있습니다.이 세트는 표에 표시된 것처럼 적어도 다음의 헤더를 포함해야 합니다.

18.1 Types <cstddef>   
18.2 Implementation properties <limits>   
18.3 Start and termination <cstdlib> 
18.4 Dynamic memory management <new> 
18.5 Type identification <typeinfo> 
18.6 Exception handling <exception> 
18.7 Other runtime support <cstdarg>

Ca 준 C++ a 내 내main함수가 필요하므로 표준 C++에 대한 질문이 의미가 없습니다.

예를 들어 표준 C++ 이외에서는 Windows 관련 프로그램을 작성하고 Microsoft의 사용자 지정 시작 기능(wMain, winMain, wWinMain) 중 하나를 사용할 수 있습니다.Windows에서는 프로그램을 DLL로 작성하고 rundll32를 사용하여 실행할 수도 있습니다.

그 외에도 작은 런타임 라이브러리를 만들 수 있습니다.한때 그것은 흔한 스포츠였습니다.

이 규칙인 ODR 규칙에 할 수 .main"사용"되지 않으므로 모든 프로그램에 적합합니다.아! 비록 면접관들이 특이한 유머 감각을 가지고 있지 않다면 (그들이 그랬다면 질문을 하지 않았을 것이다) 그들은 그것이 좋은 대답이라고 생각하지 않을 것입니다.

육안으로 볼 수 있는 주 기능이 없는 샘플 프로그램입니다.

/* 
    7050925.c 
    $ gcc -o 7050925 7050925.c
*/

#include <stdio.h>
#define decode(s,t,u,m,p,e,d) m##s##u##t
#define begin decode(a,n,i,m,a,t,e)

int begin()
{
        printf("How mainless!\n");
}

보낸 사람: http://learnhacking.in/c-program-without-main-function/

main코드 실행이 시작되는 시작점인 진입점을 의미합니다.비록 ~일지라도main실행할 첫 번째 함수가 아닙니다.이전에 실행되는 코드가 몇 개 더 있습니다.main코드가 실행되도록 환경을 준비합니다.그러면 이 코드가 호출됩니다.main의이을변수다있니습경의 할 수 .main 파일의 합니다.crt0.c그리고 이름을 바꾸는 것.main다음을 할 수 .또는 다음을 수행할 수 있습니다.

#include <stdio.h>

extern void _exit (register int code);

_start()
{
  int retval;
  retval = my_main ();
  _exit(retval);
}

int my_main(void)
{
  printf("Hello\n");
  return 0;
}

다음을 사용하여 코드를 컴파일합니다.

gcc -o no_main no_main.c -nostartfiles

-nostartfiles기본 시작 파일은 포함되지 않습니다.은 메인 을 " 본항가다니리킵을일파기목▁with▁you"로 가리킵니다._start.

main는 사용자 코드에 대해 미리 정의된 진입점일 뿐입니다.따라서 이름은 무엇이든 지정할 수 있지만 결국에는 진입점이 필요합니다.및은 C/C++ 및타언서이름다같선이다택니됩음과은으로 됩니다.main만약 당신이 다른 언어를 만들거나 이 언어 컴파일러의 소스를 해킹한다면 당신은 이름을 바꿀 수 있습니다.mainpain하지만 그것은 기준을 위반하기 때문에 고통을 가져올 것입니다.

그러나 입력 함수 이름을 조작하는 것은 커널 코드, 커널에서 실행할 첫 번째 함수 또는 임베디드 시스템용으로 작성된 코드에 유용합니다.

이들은 독립적인 구현을 위해 작성된 프로그램을 참조할 수 있습니다.C++ 표준은 두 가지 종류의 구현을 정의합니다.하나는 호스팅된 구현입니다.이러한 구현을 위해 작성된 프로그램에는 다음이 필요합니다.main기능.하지만 그렇지 않다면, 아니.main독립 실행형 구현에 필요하지 않은 경우 기능이 필요합니다.이 기능은 운영 체제 커널 또는 운영 체제에서 실행되지 않는 포함된 시스템 프로그램에 유용합니다.

네.

$ cat > hwa.S
write = 0x04
exit  = 0xfc
.text
_start:
        movl    $1, %ebx
        lea     str, %ecx
        movl    $len, %edx
        movl    $write, %eax
        int     $0x80
        xorl    %ebx, %ebx
        movl    $exit, %eax
        int     $0x80
.data
str:    .ascii "Hello, world!\n"
len = . -str
.globl  _start
$ as -o hwa.o hwa.S
$ ld hwa.o
$ ./a.out
Hello, world!

실제로 실행 파일을 실행하는 커널은 내부 기호에 대해 아무것도 알지 못하며 실행 이미지 헤더에서 이진법으로 지정된 진입점으로 전송할 뿐입니다.

메인 프로그램이 필요한 이유는 일반적으로 "메인 프로그램"이 실제로는 다른 모듈에 불과하기 때문입니다.진입점은 C와 어셈블리의 일부 조합으로 작성된 라이브러리 제공 시작 코드에 있으며 라이브러리 코드는 우연히 호출됩니다.main그래서 당신은 보통 하나를 제공해야 합니다.하지만 링커를 직접 실행하면 실행하지 않습니다.

C1 모듈을 포함하려면...

Mac:~/so$ cat > nomain.S
.text
.globl start
start:
        call   _notmain
Mac:~/so$ as -o nomain.o nomain.S
Mac:~/so$ cat > notmain.c
#include <unistd.h>

void notmain(void) {
  write(1, "hi\n", 3);
  _exit(0);
}
Mac:~/so$ cc -c notmain.c
Mac:~/so$ ld -w nomain.o notmain.o -lc
Mac:~/so$ ./a.out
hi


또한 x86-64로 전환합니다.

네, 메인 없이 컴파일은 가능하지만 링크 단계는 통과할 수 없습니다.

 g++ -c noMain.cpp -o noMain.o

용하지 않음사▁""를 ,main또한 논리가 허용되지 않음을 의미할 수 있습니다.main 러나그나main그 자체가 존재합니다.이 문제가 해결된 것으로 짐작되지만, 여기서 해결되지 않았기 때문에 다음과 같은 대답이 가능합니다.

struct MainSub
{
   MainSub()
   {
      // do some stuff
   }
};

MainSub mainSub;

int main(int argc, char *argv[]) { return 0; }

여기서 무슨 일이 일어날까요? 안에 있는 것들은MainSub의 생성자가 사용할 수 없는 사용자보다 먼저 실행됩니다.main실행되며 프로그램의 논리를 배치할 수 있습니다.물론 이것은 C가 아니라 C++이 필요합니다(질문에서도 명확하지 않습니다).

한 g++로 할 수 .-e그래서 다음 코드와 컴파일 명령은 당신이 프로그램을 만들지 않고 만들 수 있게 합니다.main()함수:

#import <iostream>

class NoMain
{
public:
    NoMain()
    {
        std::cout << "Hello World!" << std::endl;
        exit(0);
    }
} mainClass;

파일 이름을 다음과 같이 지정했습니다.noname.cpp컴파일 옵션은 다음과 같습니다.

g++ nomain.cpp -Wl,-e,_mainClass -v

사실, 저는 왜 코드가 잘 작동하는지 완전히 이해하지 못했습니다. variable의 됩니다.mainClass는 의생자동니다일의 .NoMain수업. 하지만, 나는 또한 내 추측이 틀릴 수도 있다고 말할 수 있는 몇 가지 이유가 있습니다.

매크로 참조는 메인 함수의 이름을 바꾼 것으로, 다음은 제 코드가 아니며 이를 보여줍니다.컴파일러는 여전히 주요 기능을 보고 있지만, 기술적으로는 소스 관점에서 주요 기능이 없습니다.여기서 샀어요 http://www.exforsys.com/forum/c-and-c/96849-without-main-function-how-post412181.html#post412181

#include<stdio.h>
#define decode(s,t,u,m,p,e,d) m##s##u##t
#define begin decode(a,n,i,m,a,t,e)

int begin()
{
  printf(" hello ");
}

특정 언어 표준을 무시하고 대부분의 링크 로더는 이진이 메모리에 로드될 때 실행되어야 하는 함수 이름(엔트리 포인트)을 선언하는 몇 가지 방법을 제공합니다.

오래된 학교 c 언어의 경우, 기본값은 crt(c 런타임?)에 정의된 'start' 또는 '_start'와 같은 것이었는데, 이는 메모리 힙 준비, 정적 변수 영역 초기화, argc/argv로의 명령 줄 구문 분석 등과 같은 c 표준 함수에 필요한 몇 가지 가정 작업을 수행합니다.

아마도 당신이 그러한 가정적인 것들을 요구하는 표준 함수들(예: malloc(), free(), printf(), 모든 클래스 정의에 사용자 정의 생성자가 있음)을 사용하지 않도록 충분히 주의한다면 진입점 함수를 재정의할 수 있습니다.

예를 들어 설명자 1의 write() 함수를 사용하여 간단한 hello world를 만들 수 있습니다.

C 또는 C++ 코드가 실행되면 알려진 시작 주소에서 실행되고, 여기서 코드는 런타임 환경을 초기화하고, 스택 포인터를 초기화하고, 데이터 초기화를 수행하고, 정적 생성자를 호출한 다음 main()으로 점프합니다.

이를 수행하는 코드는 링커에 의해 빌드 시 코드와 연결됩니다.GCC에서는 일반적으로 crt0.s로 되어 있으며 상용 컴파일러에서는 이 코드를 사용할 수 있을 것 같지 않습니다.

결국, 그것은 어딘가에서 시작되어야 하고 그리고.main()해당 위치의 상징적인 이름일 뿐입니다.개발자들이 그것을 무엇이라고 불러야 하는지 알기 위해 언어 표준에 의해 지정됩니다. 그렇지 않으면 코드는 한 도구 체인에서 다른 도구 체인으로 이동할 수 없습니다.

프로세스 로더의 의미에서 OS가 없거나 최소한 OS가 없는 '베어메탈' 시스템을 위한 코드를 작성하는 경우(임베디드 시스템에는 main() 이후에 시작되는 RTOS 커널이 포함되는 경우가 많습니다), 이론적으로 C 코드 입력 지점을 원하는 대로 호출할 수 있습니다.하지만 그렇게 하는 것은 어리석고 다소 비뚤어질 것입니다.

VxWorks와 같은 일부 RTOS 환경과 일반적으로 대부분의 응용 프로그램 프레임워크는 사용자 응용 프로그램 코드 이전에 실행되도록 자체 라이브러리 코드 내에 main() 또는 동등한 것을 포함합니다.예를 들어 VxWorks 애플리케이션은 usrAppInit()에서 시작하고 Win32 애플리케이션은 WinMain()에서 시작합니다.

클래스를 작성하고 해당 클래스의 생성자에 이름을 인쇄한 후 해당 클래스의 GLOBAL OBJECT를 선언합니다.따라서 클래스의 생성자는 메인 이전에 실행됩니다.메인을 비워두고 이름을 인쇄할 수 있습니다.

class MyClass
{
   myClass()
   {
       cout << "printing my name..." <<endl;
   }
};

MyClass gObj; // this will trigger the constructor.

int main()
{
   // nothing here...
}

이것이 오래된 질문이라는 것을 알지만, 저는 이것을 알게 되었고 공유해야 했습니다.모든 링커에서 작동하지는 않겠지만 적어도 속임수는 가능합니다.ld(버전 2.24.51.20140918을 실행하고 있습니다.) 이렇게 하면 주요 기능이 있다고 생각합니다.

int main[] {};

아니면 그냥

int main;

그런 다음 위에서 언급한 트릭 중 하나를 적용하여 프로그램이 생성자를 사용하여 일부 코드를 실행하도록 할 수 있습니다.

struct Main
{
    Main()
    {
        cout << "Hello World!\n";
        exit(0);
    }
} main_;

exit(0)배열이 "호출"되는 것을 방지합니다.좋은 재미야 :-)

예, C 언어의 진입점을 main()에서 _start로 변경하면 됩니다. 코드는 다음과 같습니다.

#include<stdio.h>
#include<stdlib.h>
int sid()
{
printf("Hallo World\n");
exit(0);
}

그런 다음 gcc 컴파일러를 사용하여 코드를 실행합니다.그러면 test.c라는 이름으로 파일을 저장했다고 가정하겠습니다.

gcc -nostartfiles test.c
./a.out

.data 섹션을 컴파일하여 코드로 채우는 것이 가능할까요?

그것은 그들이 의미하는 바에 따라 다릅니다.

그들이 의미한 것은:

메인() 기능이 없는 프로그램을 작성합니다.

그럼 일반적으로 말하면 안 됩니다.
하지만 속이는 방법도 있습니다.

  • 전처리기를 사용하여 일반적인 시야에서 주()를 숨길 수 있습니다.
  • 대부분의 컴파일러에서는 코드의 진입점을 지정할 수 있습니다.
    기본적으로 main(int, char*[])입니다.

아니면 그들이 의미했던 것은:

main을 사용하지 않고 코드를 실행하는 프로그램을 작성합니다(코드 실행).

이것은 비교적 간단한 속임수입니다.글로벌 네임스페이스의 모든 개체는 main()을 입력하고 main()을 종료한 후 소멸하기 전에 생성자를 실행합니다.따라서 원하는 코드를 실행하는 생성자가 있는 클래스를 정의한 다음 글로벌 네임스페이스에 개체를 만들기만 하면 됩니다.

참고: 컴파일러는 지연된 로드에 대해 이러한 개체를 최적화할 수 있지만(일반적으로 그렇지는 않습니다), 기본 함수와 동일한 파일에 글로벌을 배치하면 안전합니다(공백일 수 있음).

함수 main은 프로그램이 실행을 시작할 주소의 기본 레이블입니다.따라서 기술적으로는 가능하지만 환경에서 실행을 시작할 함수의 이름을 설정해야 합니다.

주를 정의하는 매크로 사용

#include<stdio.h>
#define fun main
int fun(void)
{
printf("stackoverfow");
return 0;
}

출력:

스택 오버플로

토큰 붙여넣기 연산자 사용 위의 솔루션에는 'main'이라는 단어가 포함되어 있습니다.메인 쓰기조차 허용되지 않는 경우 토큰 붙여넣기 연산자가 발생합니다(자세한 내용은 이 항목 참조).

#include<stdio.h>
#define fun m##a##i##n
int fun()
{
printf("stackoverflow");
return 0;
}

네, 메인 없이 프로그램을 작성하는 것이 가능합니다.

그러나 main()을 간접적으로 사용합니다.

다음 프로그램은 당신이 이해하는데 도움을 줄 것입니다.

#include<stdio.h>
#define decode(s,t,u,m,p,e,d) m##s##u##t
#define begin decode(a,n,i,m,a,r,e)
int begin()
{
printf(” you are inside main() which is hidden“);
}

'##' 연산자를 토큰 붙여넣기 연산자 또는 토큰 병합 연산자라고 합니다.즉, 두 개 이상의 문자를 병합할 수 있습니다.

프로그램의 두 번째 줄에서-

디코드 정의(s,t,u,m,p,e,d) m#s#u##t

프리프로세서는 여기서 무엇을 하고 있습니까?매크로 디코드(s,t,u,m,p,e,d)가 "msut"(## 연산자는 msut,s,u 및 t를 msut에 병합)로 확장됩니다.논리는 (s,t,u,m,p,e,d)를 인수로 전달하면 4번째,1번째,3번째 및 2번째 문자(토큰)가 병합됩니다.

이제 프로그램의 세 번째 줄을 살펴봅니다.

정의 시작 디코드(a,n,i,m,a,r,e)

여기서 전처리기는 매크로 "시작"을 확장 디코딩(a,n,i,m,a,r,e)으로 바꿉니다.이전 행의 매크로 정의에 따라 인수를 확장하여 4번째, 1번째, 3번째 및 2번째 문자를 병합해야 합니다.인수(a, n, i, m, a, r, e) 4번째, 1번째, 3번째 및 2번째 문자는 'm', 'a', 'i' 및 'n'입니다.

따라서 컴파일러에 대해 프로그램이 전달되기 전에 begin by main()을 프리프로세서로 대체합니다.바로 그거야...

C++ 생성자를 사용하면 주 함수 없이 C++ 프로그램을 작성할 수 있습니다.예를 들어 다음과 같이 주요 기능에 아무것도 쓰지 않고 hello world를 인쇄할 수 있다고 가정해 보겠습니다.

class printMe{
   private:
   //
   public:
   printMe(){
       cout<<"Hello Wold! "<<endl;
  }
       protected:
       //
 }obj;

 int main(){}

표준에 따라 main()이 필요하며 호스트 환경의 시작 지점입니다.그렇기 때문에 위에 올린 트릭처럼 뻔히 보이는 메인을 숨기기 위해 트릭을 사용해야 합니다.

#include <stdio.h>
#define decode(s,t,u,m,p,e,d) m##s##u##t
#define begin decode(a,n,i,m,a,t,e)

int begin()
{
    printf(" hello ");
}

여기서, main은 매크로 트릭에 의해 작성됩니다.한 번에 명확하지 않을 수도 있지만 결국 메인으로 이어집니다.만약 이것이 당신의 질문에 대한 유효한 답이라면, 이것은 이렇게 매우 쉽게 이루어질 수 있습니다.

# include <stdio.h>
# define m main

int m()
{
    printf("Hell0");
}

언급URL : https://stackoverflow.com/questions/7050925/is-it-possible-to-write-a-program-without-using-main-function

반응형