윈도우 프로그래밍을 하다 보면 #pragma를 자주 보게 된다. 

그러나 이를 잘 활용하기도 하겠지만 이를 잘 활용하지 못하는 사람들도 있기 때문에 이 용도를 정리 해 보고자 한다.

#pragma는 define 이나 include와 같이 #으로 시작하는 전처리구문(precompiler)의 하나이다.

컴파일러에 종속적인 구문이라 컴파일러가 변경되었을 경우 제대로된 동작을 보장하지 못하므로
 
프로젝트 진행중에 서로 다른 컴파일러를 사용한다면 사용하지 않음이 바람직 하겠다.

1. Entry Point

보통 프로그래밍을 하다보면 맨처음 시작하는 부분이 있다. 

C언어에서는 main( ... ) 함수, 윈도우즈  Programming 에서는 WinMain( ... ) 에 해당된다.

이를 EntryPoint라고 한다.

많은 문서들이 윈도우즈 어플리케이션의 진입 함수를 다음과 같은 함수로 고정된 것으로 설명하고 있다.

int WINAPI WinMain(
        HINSTANCE hInstance,
        HINSTANCE hPrevInstance,
        PSTR szCmdLine,
        int iCmdShow)


하지만 windows.h를 include하여 WinMain()을 이용하게 된다면 7KB정도의 추가적인 코드가 덧붙여 지게 된다. 

이렇게 비 생산적인 코드를 제거하려면 진입함수를 변경하면 되는데 linker에게 어떤 진입함수를 쓰는지

알려주는 방법으로 "#pragma comment" directive를 사용하면 된다.

#pragma comment()는 

#pragma comment( comment-type, ["comment string"] )

의 형태를 가지게 된다.

[] 안의 구문은 comment-type에 따라 필요할 경우 사용하는 것이다.

comment type에는 compiler, exestr, lib, linker, user 등이 올 수 있다.

linker 를 사용하면 프로젝트를 console application인지 win32 application인지 명시해줄 수 있다.

#pragma comment( linker, "/subsystem:windows" )
#pragma comment( linker, "/subsystem:console" )

또한 섹션의 설정을 할 수 있다.

#pragme comment( linker, "SECTION:.SHAREDATA,RWS" ) 

이 중 가장 대표적인 사용법은 명시적인 라이브러리의 링크이다.

#pragma comment(lib, "xxxx.lib")

이렇게 작성하여 주면 VisualStudio에서 설정없이 Library를 사용할 수 있다.

다시 Entry Point를 설정하는 예로 가보자 

#include <windows.h> 
#pragma comment (linker, "/ENTRY:main") //main부터 시작함
 
int main() 

    MessageBox(NULL, TEXT("test"), TEXT("test caption"), MB_OK); 
    return 0; 


#pragma comment (linker, "/ENTRY:main")
이렇게 하면 EntryPoint가 main으로 변경할 수 있다.

2. File Alignment


PE파일구조에서는 Section Alignment, File Alignment라는 용어를 사용하게 된다.
 
각 크기에 따라 파일상의 위치와 메모리상의 위치가 달라지게 되고 이에 따라 Pedding이 생기게 된다.

VC++ 6.0에서 default file alignment는 0x1000 바이트이다.
 
이 옵션에서는 각 section 사이에 의미없는 빈 공간을 많이 만들어 낸다. 이것은 불필요한 낭비가 아닐 수 없다.
 
만약 우리가 만드는 어플리케이션이 3개의 section(.text, data, rdata)으로 이루어져 있다면
 
최소한 0x1000 * 3 = 0x3000 = 12288 바이트나 차지한다는 의미이다.
 
0x1000 바이트 미만의 코드로 짜여진 프로그램이라면 이 역시 많은 부분이 낭비이다.
 
linker에게 FILEALIGN 옵션을 주어서 file alignment를 변경할 수 있다.

#pragma comment(linker,"/ENTRY:main /FILEALIGN:0x200 /IGNORE:4078")

위 옵션은 File Alignment를 0x200으로 주었는데 상황에 따라 적당한 겂으로 설정하면 된다.

IGNORE 옵션은 컴파일러가 4078번 에러를 반환하면 무시하라는 의미이다.
 
이렇데 PEDDING의 크기가 줄어들기 때문에 최종 실행파일 사이즈를 줄일 수 있다.

3. Section Merging

PE파일구조서도 설명되어 있지만, PE 파일 내에서 각 section에는 header, info등의 정보가
 
추가적으로 따라 붙는다.
 
만약 section들을 하나로 merge한다면 이런 추가적인 공간들을 제거할 수 있을 것이다.
 
그러나 section들을 merge할 때는 section의 내용을 정확히 파악해야 한다.

sectionDescription
.text코드 텍스트 영역
.data문자열 등이 저장되는 데이타 섹션
.rdataimage import descriptor 등이 저장되는 리소스 데이타 영역

그럼 모든 section들을 하나의 section으로 합쳐 보자.

주의할 것은 코드 텍스트 영역은 read-only 영역이고, .data나 .rdata는 쓰기 권한이 필요한 영역이므로
 
무턱대고 합치면 안되고 액세스 권한을 설정해 줘야 한다.

#pragma comment(linker,"/ENTRY:main /FILEALIGN:0x200/SECTION:.text,EWR /IGNORE:4078")

설명 속성 
ExecutableE
WriteableW
ReadalbleR

이렇게 하면 코드 영역이 executable, write, read등이 가능해 지도록 하는 것이다.
 
실제로 section을 머지하는 옵션은 다음과 같다.

#pragma comment(linker,"/ENTRY:main /FILEALIGN:0x200 
                        /MERGE:.data=.text      //.data가 .text로 합쳐짐
  /MERGE:.rdata=.text     //.rdata가 .text로 합쳐짐
                       /SECTION:.text,EWR /IGNORE:4078") 


4. 헤더 중복막기

프로그래밍을 할 때 .h .cpp파일로 나눠서 사용한다.
 
그리고 .h파일의 중복때문에 컴파일시 에러가 생기는경우가 발생한다. 

c언어에서는 

#ifndef _TEST_H_
#define _TEST_H_

#endif

이렇게 사용가능하며, CPP에서는 이를 막기위해

#pragma once

를 사용한다. 그래서 헤더파일의 중복을 막게 된다.

5. 경고없애기

VisualStudio에서 코딩을 하다 보면 경고가 뜰 때가 있다. 

이 경고문에 대해서 프로그래머가 아는 경고문일때 이를 컴파일러에게 명시해 줄 때 사용한다.

#pragma warning( disable:4996 )

AND