전처리기 지시문

tangoo·2022년 4월 29일
0

C#

목록 보기
3/7
post-thumbnail

C# 전처리기 지시문(preprocessor directive) 란 무엇일까?

간단히 말하면 주로 특정 소스코드를 상황에 따라 컴파일 과정에서 추가/제거하고 싶을 때 사용한다.

static void Main(String[] args)
{
		string txt = Console.ReadLine();

		if(string.IsNullOrEmpty(txt) =false)
		{
		Console.WriteLine("사용자 입력 : "+txt)'
		}

}

코드를 보면, Enter 키가 눌릴 때 따지 키보드를 입력 받아서 Console.ReadLine메서드가 실행되면 입력값 내부에 저장했다가 Enter키 눌르면 반환한다. string.IsNullOrEmpty 메서드 인자는 string 객체가 null 또는 “ ”(빈 문자열) 이면 true, 아니면 false를 반환하는 코드이다.

그런데 아무입력도 받지 않은 경우에 특정 메세지를 출력하고 싶다면 어떻게해야할까?

내가 생각하기에는 보통 if-else 문을 사용할 것이다.

if(string.IsNullOrEmpty(txt) ==false)
{
	Console.WriteLine("사용자 입력" +txt);
}
else Console.WriteLine("입력 없음");

그런데 이런 변경을 원하지 않는다면? .cs 파일을 2개로 나눠서 각 다른 파일로 생성하고 관리해야하는데 그러면 여러가지 문제가 발생한다. 그 중 아마 가장 큰 문제는 변경 사항 관리이다. 예를 들어 p1.cs, p2.cs가 있다고 하자, p1.cs의 코드 변경사항이 생긴다면, p2.cs에도 반영을 해야하는 번거러움이 생긴다.

이런 번거러움을 해결하기 위해서 우리는 전처리기 지시문을 사용한다.

그런데 전처리기 지시문은 우린 이미 사용해 본적이 있다.

#define AGE 10

코딩 테스트나 C나 C++ 공부할 때 사용해 본 경험이 있을 것이다.

이런거를 #if #else 등등으로 쓰는 것일 뿐이다. 같은 것이다.

앞서 계속 설명하고 있던 코드를 전처리기 지시문을 사용해서 바꿔보겠다.

static void Main(String[] args)
{
string txt = Console.ReadLine();
if(string.IsNullOrEmpty(txt) ==false)
	{
		Console.WriteLine("사용자 입력" +txt);
	}
#OUTPUT_LOG
else 
	{
		Console.WriteLine("입력 없음");
	}
#endif
}

OUTPUT_LOG 전처리기 상수가 정의되어 있다면 #if #endif 사이의 소스코드를 포함해서 컴파일하게 만들고, 정의 안되어 있으면 컴파일 과정에서 제거한다.

차이가 뭐냐면,

-OUTPUT_LOG가 정의되어 있지 않다면 csc p1.cs로 나타내어지고,

-OUTPUT_LOG가 정의되어 있다면 csc/define:OUTPUT_LOG p1.cs로 나타내어진다.

이렇게 전처리기를 사용하면 하나의 소스코드 파일로 여러가지 상황을 만족하는 프로그램을 만들 수 있다.

다음은 여러가지 전처리기 지시자가 있다.

#define __x86__
#undef OUTPUT_LOG
#if OUTPUT_LOG
#else
#endif
#if __x86__
#elif __x64__
#warning 
#error
#line
#region
#endregion
#pragma 
  • #if: 지정된 기호가 정의된 경우에만 코드가 컴파일되는 조건부 컴파일을 연다.
  • #elif: 앞에 있는 조건부 컴파일을 닫고 지정된 기호가 정의되었는지에 따라 새 조건부 컴파일을 연다.
  • #else: 앞에 있는 조건부 컴파일을 닫고 이전 지정된 기호가 정의되지 않은 경우 새 조건부 컴파일을 연다.
  • #endif: if 지시문으로 시작한 조건부 지시문의 끝을 지정하고, 앞에 있는 조건부 컴파일을 닫는다.
  • #define: 기호를 정의한다.
  • #undef: 기호 정의를 취소한다.
  • #region: 영역을 시작한다.
  • #endregion: 영역을 종료한다.
  • #error: 지정된 메시지를 사용하여 컴파일러 오류를 생성한다.
  • #warning: 지정된 메시지를 사용하여 컴파일러 경고를 생성한다.
  • #line: 컴파일러 메시지를 사용하여 출력된 줄 번호를 변경한다.

참고자료 : Microsoft 문서에 더 자세히 나와있다.
C# 전처리기 지시문

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class MainMenu : MonoBehaviour
{
    public void OnClickLanding() => SceneManager.LoadScene("Stage1");

    public void OnClickStart() => SceneManager.LoadScene("LoadScene");

    public void OnClickQuit()
    {
#if UNITY_EDITOR
        UnityEditor.EditorApplication.isPlaying = false;
#else
        Application.Quit();
#endif
    }
}

그럼 이를 유니티의 소스 파일에서도 적용 시킬 수 있다.

위의 코드는 클릭하면 stage1로, 또다른 것을 클릭하면 loadScene으로 씬이동을해주고, Quit버튼을 클릭하면 종료해주는 코드이다.

Quit버튼을 클릭하면 #if UNITY_EDITOR 유니티 에디터 환경에서 실행하였을 때의 Quit버튼을 누른다면 유니티에디터내의 Playing을 false로 나타내어 종료시키고,

다른 것이라면 유니티에서 게임을 종료하기 위해서 사용되는 Application 클래스의 Quit함수를 사용하여 종료 시킨다.

왜 꼭 이렇게 해야하는가?

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class MainMenu : MonoBehaviour
{
    public void OnClickLanding() => SceneManager.LoadScene("Stage1");

    public void OnClickStart() => SceneManager.LoadScene("LoadScene");

    public void OnClickQuit()
    {
				Application.Quit();
    }
}

이렇게 사용하여 쓴다면, 빌드한 어플리케이션에서는 정상적으로 종료가 되지만, 유니티 에디터에서는 게임 플레이 종료가 되지 않는 문제점이 있다.

그러므로 필자는 유니티에디터에서의 종료와 어플리케이션의 종료 둘 다 실행시키기 위해 서로 다른 환경에서의 코드를 구현하기 위해서 에디터와 프로그램 실행 플랫폼을 구분지어서 전처리기를 사용하여 코딩하는 것을 추천한다.

profile
안녕하세요!

0개의 댓글