#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("Ha HA see how it is?? ");
}
이것은 간접적으로 호출 main
합니까? 어떻게?
답변
C 언어는 독립형 및 호스트 형의 두 가지 범주로 실행 환경을 정의합니다 . 두 실행 환경 모두에서 프로그램 시작을 위해 환경에 의해 함수가 호출됩니다.
A의 자립 환경 프로그램 기동 기능 구현 중에 정의 될 수 호스팅 환경이 있어야한다 main
. 정의 된 환경에서 프로그램 시작 기능 없이는 C 프로그램을 실행할 수 없습니다.
귀하의 경우 main
에는 전 처리기 정의에 의해 숨겨져 있습니다. begin()
에 확장됩니다 decode(a,n,i,m,a,t,e)
더 확장 될 것이다 main
.
int begin() -> int decode(a,n,i,m,a,t,e)() -> int m##a##i##n() -> int main()
decode(s,t,u,m,p,e,d)
7 개의 매개 변수가있는 매개 변수화 된 매크로입니다. 이 매크로의 대체 목록은 m##s##u##t
입니다. m, s, u
및 t
(4)이다 일 , 1 일 , 3 번째 및 2 차 교체리스트에 사용되는 파라미터.
s, t, u, m, p, e, d
1 2 3 4 5 6 7
나머지는 소용이 없습니다 ( 단지 난독 화하기 위해 ). 에 전달 인자 decode
“이다 , N , I는 , m이 때문에, 식별자, A, t, E는” 과는 인수로 대체 하고 각각.m, s, u
t
m, a, i
n
m --> m
s --> a
u --> i
t --> n
답변
사용 시도 gcc -E source.c
와 함께, 출력단을 :
int main()
{
printf("Ha HA see how it is?? ");
}
따라서 main()
함수는 실제로 전처리기에 의해 생성됩니다.
답변
문제의 프로그램은 수행 전화를 main()
인해 매크로 확장에, 그러나 당신의 가정은 결함이 – 그것은 하지 않습니다 호출 할 필요가 main()
전혀!
엄밀히 말하면, C 프로그램을 가지고 main
심볼 없이 컴파일 할 수 있습니다 . main
는 c library
자체 초기화를 마친 후 점프 할 것으로 예상되는 것입니다 . 일반적으로 main
libc 기호에서 _start
. main없이 어셈블리를 실행하는 매우 유효한 프로그램을 항상 가질 수 있습니다. 이것 좀보세요 :
/* This must be compiled with the flag -nostdlib because otherwise the
* linker will complain about multiple definitions of the symbol _start
* (one here and one in glibc) and a missing reference to symbol main
* (that the libc expects to be linked against).
*/
void
_start ()
{
/* calling the write system call, with the arguments in this order:
* 1. the stdout file descriptor
* 2. the buffer we want to print (Here it's just a string literal).
* 3. the amount of bytes we want to write.
*/
asm ("int $0x80"::"a"(4), "b"(1), "c"("Hello world!\n"), "d"(13));
asm ("int $0x80"::"a"(1), "b"(0)); /* calling exit syscall, with the argument to be 0 */
}
위를로 컴파일하고 인라인 어셈블리에서 시스템 호출 (인터럽트)을 실행하여 화면에 gcc -nostdlib without_main.c
인쇄 Hello World!
되는 것을 확인하십시오 .
이 특정 문제에 대한 자세한 내용은 ksplice 블로그를 확인하십시오.
또 다른 흥미로운 문제 main
는 C 함수에 해당 하는 기호 없이 컴파일되는 프로그램을 가질 수도 있다는 것 입니다. 예를 들어 다음을 매우 유효한 C 프로그램으로 사용할 수 있으며 경고 수준이 올라갈 때만 컴파일러가 우는 소리를냅니다.
/* These values are extracted from the decimal representation of the instructions
* of a hello world program written in asm, that gdb provides.
*/
const int main[] = {
-443987883, 440, 113408, -1922629632,
4149, 899584, 84869120, 15544,
266023168, 1818576901, 1461743468, 1684828783,
-1017312735
};
배열의 값은 Hello World를 화면에 인쇄하는 데 필요한 지침에 해당하는 바이트입니다. 이 특정 프로그램의 작동 방식에 대한 자세한 설명은이 블로그 게시물을 참조 하십시오.
이 프로그램에 대해 마지막으로 알려 드리고 싶습니다. C 언어 사양에 따라 유효한 C 프로그램으로 등록되어 있는지는 모르겠지만, 사양 자체를 위반하더라도 컴파일하고 실행하는 것은 확실히 가능합니다.
답변
누군가 마술사처럼 행동하려고합니다. 그는 우리를 속일 수 있다고 생각합니다. 그러나 우리 모두는 c 프로그램 실행이 main()
.
는 int begin()
대체 될 decode(a,n,i,m,a,t,e)
전처리 단계 중 하나 개를 통과하여. 그런 다음 다시 decode(a,n,i,m,a,t,e)
m ## a ## i ## n으로 대체됩니다. 매크로 호출의 위치 연관과 마찬가지로 s
will의 값은 character a
입니다. 마찬가지로 u
‘i’ t
로 대체되고 ‘n’으로 대체됩니다. 그리고 그렇게 m##s##u##t
될 것입니다.main
관한 ##
매크로 팽창 기호는 전처리 연산자이며 토큰 붙여 넣기를 행한다. 매크로가 확장되면 각 ‘##’연산자의 양쪽에있는 두 개의 토큰이 단일 토큰으로 결합 된 다음 매크로 확장에서 ‘##’및 두 개의 원래 토큰을 대체합니다.
나를 믿지 않는다면 -E
플래그로 코드를 컴파일 할 수 있습니다 . 전처리 후 컴파일 과정이 중단되고 토큰 붙여 넣기 결과를 볼 수 있습니다.
gcc -E FILENAME.c
답변
decode(a,b,c,d,[...])
처음 4 개의 인수를 섞고 결합하여 순서대로 새 식별자를 얻습니다 dacb
. (나머지 세 개의 인수는 무시됩니다.) 예를 들어, decode(a,n,i,m,[...])
식별자를 제공합니다 main
. 이것이 begin
매크로가 정의 된 것입니다.
따라서 begin
매크로는 간단히 main
.
답변
귀하의 예제에서는 컴파일러가 매크로로 대체하고 차례로 m ## s ## u ## t 표현식으로 대체되는 매크로 main()
이므로 함수가 실제로 존재 begin
합니다 decode
. 매크로 확장을 사용하면 from ##
이라는 단어에 도달하게 main
됩니다 decode
. 이것은 추적입니다.
begin --> decode(a,n,i,m,a,t,e) --> m##parameter1##parameter3##parameter2 ---> main
를 갖는 것은 단지 속임수 main()
이지만 main()
C 프로그래밍 언어에서는 프로그램의 입력 함수에 이름 을 사용할 필요가 없습니다. 운영 체제와 해당 도구 중 하나 인 링커에 따라 다릅니다.
Windows에서 항상 사용하지 않는 main()
하지만, 오히려 WinMain
나wWinMain
있지만, 사용할 수있는 main()
, 심지어 마이크로 소프트의 툴 체인과 함께 . Linux에서는 _start
.
언어 자체가 아니라 진입 점을 설정하는 운영 체제 도구로서의 링커에 달려 있습니다. 당신도 할 수 있습니다 우리 자신의 진입 점을 설정하고, 또한 실행 가능한 라이브러리를 만들 수 있습니다 !