728x90
[in,out] 배열을 C# 에서 C/C++ 로 넘기는 방법



가령, long 형 배열을 C/C++에 넘겨주고, C/C++ 측에서 해당 배열의 내용을 채운 후 반환해 주는 메서드라면 다음과 같이 IDL 정의를 해줄 수 있습니다.

[
	object,
	uuid(1A38076B-3D6D-4F20-8B4D-C72EF6AE1204),
	dual,
	nonextensible,
	helpstring("IMyTest Interface"),
	pointer_default(unique)
]
interface IMyTest : IDispatch
{
	[id(0x3003), helpstring("method PrepareBuf1")] 
	HRESULT PrepareBuf([in, out, size_is(bufLength)] __int64 buffer [], [in] int bufLength);
};


그런데, tlbimp.exe (또는 Visual Studio의 DLL 참조)를 이용하여 interop DLL을 생성해 보면, PrepareBuf 의 함수 형식이 다음과 같이 정의되는 것을 볼 수 있습니다.

tlbimp testatl.dll /out:interop.testatl.dll

public virtual void PrepareBuf(ref long buffer, int bufLength);


오호... tlbimp.exe로써는, 감당이 안되는 IDL 구문이라는 것인데요. 그렇다면 이를 해결하기 위해서 생각해 볼 수 있는 것이 배열 자체를 포인터로 넘겨보는 정도일텐데, 약간 찜찜하긴 해도 4byte(혹은 8byte) 값으로 넘기는 것은 ^^ 너무 잘 동작합니다.

그래서 C# 측에서, 배열 자체를 IntPtr로 변경하고,

[STAThread]
static void Main(string[] args)
{
    interop.testatl.MyTestClass mtc = new interop.testatl.MyTestClass();
    
    long [] test = new long[5];
    IntPtr ptr = Marshal.UnsafeAddrOfPinnedArrayElement(test, 0);
    mtc.PrepareBuf(ptr.ToInt64(), 5);
    for (int i = 0; i < 5; i++)
    {
        Console.WriteLine(test[i]);
    }
}


C/C++ 에서는 넘겨받은 정수값을 간단하게 포인터로 형변환해서 처리해 주면 됩니다.

STDMETHOD(PrepareBuf2)(__int64 buffer, int bufLength)
{
	__int64 *pBuffer = (__int64 *)buffer;

	for (int i = 0; i < bufLength; i ++ )
	{
		pBuffer[i] = i;
	}

	return S_OK;
}


물론, 이 방법은 out-of-process COM 개체로 만들면 프로세스 주소 공간이 달라지기 때문에 동작하지 않습니다. 하지만, In-proc COM 개체만으로 사용하실 분들이라면 이 방법이 나쁘다고 볼 수는 없습니다.



출처 : http://www.sysnet.pe.kr/Default.aspx?mode=2&sub=0&pageno=0&detail=1&wid=810

728x90
728x90

저의 경우, VC++ 8.0 의 C++/CLI 에 대한 매력을 느끼게 된 것은 문맥 구문이니... 뭐 그런 것들이 아니었습니다. 바로 명시적인 delete 구문의 지원이었습니다. 어떻게 그것이 가능할까... 뭔가 Interop 간에 대단한 비밀이 있지 않나 싶었는데요. 역시 파고들어 보니... 결국 ^^; IL 코드내에서 해결할 수 있을 뿐이더군요. (이제와서는, 명시적인 종료자보다 IJW 를 구현한 것에 대해 더 칭찬을 해주고 싶습니다.)

우선, 본격적으로 들어가기에 앞서 미리 다음의 토픽을 먼저 봐주시기 바랍니다.

.NET IDisposable 처리 정리 
http://www.sysnet.pe.kr/Default.aspx?mode=2&sub=0&pageno=0&detail=1&wid=347

사실, 도움말에도 나타난 위의 토픽을 굳이 한번 더 언급한 것은 이번 토픽을 위해서였습니다.



그럼, 하나씩 한번 알아볼까요? ^^

우선 예제 코드가 하나 있어야 할테니, 다음과 같은 클래스를 만들어서 예로 들어보겠습니다.

public ref class MyClass 
{
public:

	MyClass()
	{
	}
};


아래는 위의 코드를 사용하느 main 함수입니다.

int main(array ^args)
{
	MyClass ^myClass = gcnew MyClass();
    return 0;
}


일단, 여기 까지는 크게 일반 C#/VB.NET 클래스와 다른 점이 없습니다. 그런데, 여러분이 (또는 과거의 제가) 어렴풋이 들었던 것 중에, C++/CLI 에서는 delete 구문으로 개체를 명시적으로 해제하는 것을 지원한다고 했지요. 그래서 다음과 같이 delete 를 추가해 보겠습니다.

int main(array ^args)
{
	MyClass ^myClass = gcnew MyClass();
	delete myClass;
    return 0;
}


과연 정말 그럴까요? 위와 같이 하면 CLR Heap 에 할당된 개체가 즉시 삭제되어 메모리 관리 효율이 C++ 과 같아질 수 있을까요? 물론... 대답은 "아니오" 입니다. 실제로, 위의 코드 부분에 대해서 ".NET Reflector" 로 보면 다음과 같이 delete 코드가 확장되어 나오는 것을 확인할 수 있습니다.

internal static int main(string[] args)
{
      MyClass class1 = null;
      class1 = new MyClass();
      IDisposable disposable1 = class1 as IDisposable;
      if (disposable1 != null)
      {
            disposable1.Dispose();
      }

      return 0;
}


위의 코드를 보시고, ^^; 쓴 웃음을 짓는 분도 계실 텐데요. 그렇습니다. "delete myClass;" 구문은 실제로는 해당 개체의 IDisposable 인터페이스 구현여부를 알아내서 그것의 Dispose 메서드를 호출해주는 코드로 대체되어 삽입되는 것 뿐입니다. 이건 사실 기술이라고 부를 수도 없지요. 단지 언어적인 확장에 기인한 것 뿐이니까요. 마치 C# 의 경우 using 예약어를 지원하지만, 결국 생성된 코드는 try / finally 에 Dispose 메서드를 불러주는 코드로 확장되는 것과 다를 바 없습니다. 실제로, 우리가 기대했던 CLR Heap 의 메모리 정리 상황은 발생하지 않는 다는 것이 중요할 것입니다. 위의 방식을 아셨으니, 이제 쓰게 될 나머지 부분은 다 그러한 부분의 확장으로 받아들이시면 이해가 금방 되실 텐데요.

가만 있자... 그럼 또 뭐가 있을까요? 그렇군요. 우리가 알고 있던 얘기 중에, C++/CLI 는 파괴자를 구현하면 scope 을 벗어나는 경우 자동으로 호출된다고 들었지요. 그럼 그 부분도 한번 살펴볼까요? 예를 위해 위의 코드를 다음과 같이 수정해 보겠습니다.

public ref class MyClass 
{
	char *m_pBuf;
public:

	MyClass()
	{
		m_pBuf = new char[ 4096 ];
	}

	~MyClass()
	{
		delete [] m_pBuf;
	}
};


scope 을 벗어나는 것을 테스트 하기 위해서 MyClass 에 대한 명시적인 delete 없이 다음과 같은 스택 방식으로 수정을 하겠습니다.

int main(array ^args)
{
	MyClass myClass;
	return 0;
}


역시 이번에도 생성된 IL 코드를 ".NET Reflector" 로 확인해 보겠습니다.

internal static int main(string[] args)
{
      int num2;
      MyClass class1 = null;
      MyClass modopt(IsConst) local1 = (MyClass modopt(IsConst)) new MyClass();
      try
      {
            class1 = local1;
            num2 = 0;
      }
      fault
      {
            class1.Dispose();
      }
      class1.Dispose();
      
      return num2;
}


오... 이런... ^^; 역시 이번에도 실제로는 Managed 클래스를 스택상에 생성하지 않고 CLR Heap 에 할당하고는 fault 처리기에서 Dispose 가 명시적으로 불릴 수 있도록 하는 IL 코드로 확장이 되었습니다. 
재미있는 것은, MyClass 를 IL 코드로 열어보면 C++ 구문의 파괴자를 구현한 것이 실제로는 다음과 같이 IDisposable 패턴으로 확장된 것을 볼 수 있습니다.

public class MyClass : IDisposable
{
      public MyClass();
      private void ~MyClass();
      public sealed override void Dispose();
      protected virtual void Dispose([MarshalAs(UnmanagedType.U1)] bool);

      private unsafe sbyte modopt(IsSignUnspecifiedByte)* m_pBuf;
}


패턴은 이전 토픽에서 살펴봤던 C# 과 동일한 구조를 따르고 있습니다.

정리해 보면, C++/CLI 의 자원해제 기능은 결국 C++ 과 유사한 구문을 그대로 유지하되 내부적으로는 IDisposable 구문으로 확장해주는 것에 불과하다는 것입니다.

즉, C++/CLI 에서 다음과 같이 코딩을 한 것은,

	MyClass ^myClass = gcnew MyClass();
	delete myClass;
	
	또는,
	
	MyClass myClass;


C# 으로 다음과 같이 코딩을 해줄 수가 있습니다.

  using ( MyClass myClass = new MyClass() )
  {
  }  


C++/CLI 에서는 단지 구문을 단순하게 해준다는 장점만 있을 뿐, 그 이외의 어떠한 장점도 없다는 것입니다.



이미 앞에서 다뤘던 .NET IDisposable 처리 정리의 토픽과 비교해 보시면 아직 얘기하지 않은 이야기가 하나 있음을 아시게 될 텐데요. 바로 Managed 자원 해제와 Unmanaged 자원해제를 구분지어 해제하는 방법이 과연 무엇이냐는 것입니다. C# 의 경우, IDisposable 인터페이스를 구현하고 내부적으로 Dispose(bool disposing) 메서드를 호출하는데, C++/CLI 에서는 IDisposable 인터페이스를 자동으로 구현하기 때문에 bool disposing 에 대한 처리를 하는 부분이 모호해 지기 때문입니다. 이를 위해, C++/CLI 에서는 다음과 같은 특별한 구문의 파괴자를 하나 더 지원합니다.

public ref class MyClass 
{
	char *m_pBuf;
public:

	MyClass()
	{
		m_pBuf = new char[ 4096 ];
	}

	~MyClass()
	{
		// Managed 자원과 Unmanaged 자원을 모두 해제
		delete [] m_pBuf;
	}

	!MyClass()
	{
		// Unmanaged 자원을 해제
		delete [] m_pBuf;
	}
};


이 부분에서 약간 재미난 현상을 만나게 되는데요. Unmanaged 자원에 대한 해제 코드를 중복시키지 않기 위해 ~MyClass 에서 !MyClass 를 아래와 같이 호출하게 되면 컴파일 오류가 발생하게 됩니다.

	~MyClass()
	{
		!MyClass(); // error C2088: '!' : illegal for class	d:\...\Test.h
	}

	!MyClass()
	{
		delete [] m_pBuf;
	}


대신에 다음과 같이 포인터 구문을 쓰게 되면 정상적으로 호출이 됩니다.

	~MyClass()
	{
		this->!MyClass(); // 또는 MyClass::!MyClass();
	}

	!MyClass()
	{
		delete [] m_pBuf;
	}




이로써, C++/CLI 의 명시적인 종료자에 대해서 왠만큼 살펴본 것 같은데요. 
결론을 내려보면. C++/CLI 가 자원 해제 면에서 결코 우수한 언어가 아님을 알게 됩니다. 그저 Interop 만 우수한 언어일 뿐.


출처 : http://www.sysnet.pe.kr/Default.aspx?mode=2&sub=0&pageno=1&title=%25c%2B%2B%25&wid=349&detail=1

728x90
728x90
728x90
728x90

http://www.csharpstudy.com/

728x90

'Basic Programming > C#' 카테고리의 다른 글

C# - 작업 스케줄러에 등록하기  (0) 2021.12.10
C# - Steam Game 실행하기  (0) 2020.07.21
C# - Dispose  (0) 2018.10.12
C# - WeakReference  (0) 2018.10.11
C# - Attibute  (0) 2018.07.09
728x90
1. constexpr


기존의 const 보다 훨씬 더 상수성에 충실하며, 컴파일 타임 함수를 이용한 성능 향상 등 충분히 깊게 이해할만한 가치가 있는 녀석이라 할 수 있으니, 확실히 이해하고 활용할 수 있는 것이 중요하다.

C++11부터 지원되는 한정자 constexpr는 일반화된 상수 표현식(Generalized constant expression)을 사용할 수 있게 해주며, 일반화된 상수 표현식을 통해 변수나 함수, 생성자 함수에 대하여 컴파일 타임에 평가될 수 있도록 처리해 줄 수 있다.
(C++17부터는 람다 함수에도 constexpr 키워드 사용이 가능하다)

constexpr 변수 또는 함수의 반환값은 반드시 LiteralType이어야 하며, LiteralType은 컴파일 타임에 해당 레이아웃이 결정될 수 있는 타입을 의미한다. 다음은 리터럴 타입들의 유형이다.
  • void
  • 스칼라 값
  • 참조
  • void, 스칼라 값, 참조의 배열
  • trivial 소멸자 및 이동 또는 복사 생성자가 아닌 constexpr 생성자를 포함하는 클래스. 또한 해당 비정적 데이터 멤버 및 기본 클래스가 모두 리터럴 타입이고 volatile이 아니어야 함

코드 작업 중 해당 타입이 리터럴 타입인지 확인하고 싶을 땐, std::is_literal_type을 사용하면 된다.


1) 변수에서의 사용

const와 constexpr의 주요 차이점은 const 변수의 초기화를 런타임까지 지연시킬 수 있는 반면, constexpr 변수는 반드시 컴파일 타임에 초기화가 되어 있어야 한다.
초기화가 안 되었거나, 상수가 아닌 값으로 초기화 시도시 컴파일이 되지 않는다.

  1. constexpr float x = 42.f;    // OK
  2. constexpr float y { 108.f }; // OK
  3. constexpr int i;             // error C2737: 'i': 'constexpr' 개체를 초기화해야 합니다.
  4. int j = 0;
  5. constexpr int k = j + 1;     // error C2131 : 식이 상수로 계산되지 않았습니다.

변수에 constexpr 사용시 const 한정자를 암시한다.


2) 함수에서의 사용

constexpr을 함수 반환값에 사용할 때는 다음의 제약들이 따른다.
  • 가상으로 재정의된 함수가 아니어야 한다.
  • 반환값의 타입은 반드시 LiteralType이어야 한다.

함수에 constexpr을 붙일 경우 inline을 암시한다.
즉, 컴파일 타임에 평가하기 때문이며, inline 함수들과 같이 컴파일된다.

C++11에서는 함수 본문에 지역변수를 둘 수 없고, 하나의 반환 표현식만이 와야 하는 제약이 있었으나, C++14부터는 이러한 제약이 사라졌다.

  1. // C++11/14 모두 가능
  2. constexpr int factorial(int n)
  3. {
  4.     // 지역 변수 없음
  5.     // 하나의 반환문
  6.     return n <= 1 ? 1 : (* factorial(- 1));
  7. }
  8.  
  9. // C++11에서는 컴파일 에러 발생
  10. // C++14부터 가능
  11. constexpr int factorial(int n)
  12. {
  13.     // 지역 변수
  14.     int result = 0;
  15.  
  16.     // 여러 개의 반환문
  17.     if (<= 1)
  18.         result = 1;
  19.     else
  20.         result = n * factorial(- 1);
  21.  
  22.     return result;
  23. }

constexpr 함수는 컴파일러에게 가능하다면, 상수시간에 컴파일해 달라고 요청하는 것이지만 상황에 따라 컴파일 타임에 미리 실행될 수도 있고, 그렇지 못하고 런타임에 실행될 수도 있다.
(마치 inline 키워드가 그러하듯이 말이다)

constexpr의 함수 인자들이 constexpr 규칙에 부합하지 못하는 경우엔 컴파일 타임에 실행되지 못하고 런타임에 실행된다.
런타임 실행 여부는 여러 가지 방식으로 검증해 볼 수 있다.
  • breakpoint 걸어서 중단되는지 확인
  • 아래 예제의 constN 같은 테스팅 템플릿 작성
  • 정수일 경우 배열의 dimension으로 작성

  1. // 템플릿 인자 N이 컴파일 타임 상수인지 테스트하기 위한 템플릿 구조체
  2. template<int n>
  3. struct constN
  4. {
  5.     constN() { std::cout << N << '\n'; }
  6. };

  7. constexpr int factorial(int n)
  8. {
  9.     return n <= 1 ? 1 : (* factorial(- 1));
  10. }
  11.  
  12. int main()
  13. {
  14.     // 4는 리터럴 타입이므로 상수 타임에 컴파일 성공
  15.     constN<factorial(4)> out1;
  16.  
  17.     // ab는 4의 값을 가지지만, 리터럴 타입이 아니므로 컴파일 에러 발생
  18.     // error C2975: 'N': 'constN'의 템플릿 인수가 잘못되었습니다. 컴파일 타임 상수 식이 필요합니다.
  19.     int ab = 4;
  20.     constN<factorial(ab)> out2;
  21.  
  22.     // 리터럴 타입이 아니므로, 이 함수는 런타임에 실행된다.
  23.     // 하지만 정상 동작한다.
  24.     int cd = factorial(ab);
  25.  
  26.     return 0;
  27. }

25라인에서 factorial 함수의 인자가 constexpr로 평가될 수 없기에, 함수이지만 런타임에 실행되는 것을 확인할 수 있다. 
이처럼 constexpr 함수는 인자가 constexpr에 부합한지에 따라, 컴파일 타임 또는 런타임에 실행되기에 범용적으로 사용되는 함수이고, 실행의 복잡도가 낮지 않다면, 가급적 constexpr 키워드를 붙이는 것도 괜찮은 습관이 되지 않을까 생각한다.

위의 예제에서는 함수가 어느 시점에 실행되는지 여부를 살펴보았지만, 무작정 constexpr 키워드를 붙일 수 있는 것도 아니다.
함수가 절대 상수표현식으로써 평가받지 못하는 문맥을 가지는 경우엔 컴파일 에러가 발생한다.

  1. constexpr int rand_short()
  2. {
  3.     // 절대 상수화가 될 수 없는 문맥
  4.     // error C3615: constexpr 함수 'randshort'의 결과가 상수 식이면 안 됩니다.
  5.     return rand() % 65535;
  6. }

컴파일 에러니까 함수 작성 후 바로 확인이 가능하기에 심각한 오류를 사전에 만나는 일은 없을 것이다.


3) 생성자 함수에서의 사용

LiteralType 클래스를 생성할 때 constexpr 생성자를 사용할 수 있다.
이 때의 제약은 다음과 같다.
  • 모든 생성자 함수의 매개변수들 역시 LiteralType들이어야 한다.
  • 어떤 클래스로부터 상속받지 않아야 한다

constexpr이 적용된 함수의 매개변수는 반드시 LiteralType이어야 한다고 했다.
이를 만족시키기 위해 constexpr 생성자 함수를 이용, LiteralType 클래스를 활용하는 예제를 살펴보도록 하자.

  1. // 아래 CountLowercast 함수의 인자로 사용하기 위한 LiteralType class
  2. class ConstString
  3. {
  4. private:
  5.     const char* p = null;
  6.     std::size_t sz = 0;
  7.  
  8. public:
  9.     template<std::size_t N>
  10.     constexpr ConstString(const char(&a)[N])
  11.     : p(a), sz(- 1)
  12.     {
  13.     }
  14.  
  15. public:
  16.     constexpr char operator[](std::size_t n) const
  17.     {
  18.         return n < sz ? p[n] : throw std::out_of_range("");
  19.     }
  20.  
  21. public:
  22.     constexpr std::size_t size() const { return sz; }
  23. };
  24.  
  25. // 소문자가 몇개인지 수를 세는 함수
  26. constexpr std::size_t CountLowercase(ConstString s, std::size_t n = 0, std::size_t c = 0)
  27. {
  28.     return n == s.size() ?
  29.                     c :
  30.                     s[n] >= 'a' && s[n] <= 'z' ?
  31.                         CountLowercase(s, n+1, c+1) :
  32.                         CountLowercase(s, n+1, c);
  33. }
  34.  
  35. // 컴파일타임 상수를 테스트해 보기 위한 템플릿
  36. template<int n>
  37. struct ConstN
  38. {
  39.     ConstN()
  40.     {
  41.         std::cout << n << '\n';
  42.     }
  43. };
  44.  
  45. int main()
  46. {
  47.     std::cout << "Number of lowercase letters in \"Hello, world!\" is ";
  48.  
  49.     // "Hello, world!"가 ConstString으로 암시적 형반환되어, CountLowercase 함수의 인자로 넘어감.
  50.     // CountLowercase는 컴파일 타임에 평가되었고, 그 결과를 가지고 ConstN 역시 컴파일 타임에 결정됨.
  51.     ConstN<CountLowercase("Hello, world!")> out;
  52.  
  53.     return 0;
  54. }


2. 템플릿 메타 프로그래밍 vs constexpr

constexpr은 컴파일 타임에 평가되기 때문에 템플릿 메타 프로그래밍(템플릿 함수가 인스턴스화될 때 값 계산)과 비교될 수 있다.
예를 들어, 똑같이 배열의 크기나 enum 열거형의 값과 같은 곳에서 상수로써 사용이 가능하다.

  1. // 템플릿 함수 방식의 Factorial
  2. template <int N>
  3. struct Template_Factorial
  4. {
  5.     enum { value = N * Template_Factorial<- 1>::value; }
  6. };
  7.  
  8. template <>
  9. struct Template_Factorial<0>
  10. {
  11.     enum { value = 1; }
  12. }
  13.  
  14. // constexpr 방식의 Factorial
  15. constexpr int Constexpr_Factorial(int n)
  16. {
  17.     return n <= 0 ? 1 : n  * Constexpr_Factorial(- 1);
  18. }
  19.  
  20. // constexpr 함수의 결과를 enum의 값으로 사용 가능
  21. enum FACTORIAL
  22. {
  23.     first  = Constexpr_Factorial(1),
  24.     second = Constexpr_Factorial(2),
  25.     third  = Constexpr_Factorial(3),
  26. };

위 예제에서 보듯이, 기존의 TMP에서 0과 같은 특수값을 사용하기 위해 템플릿 특수화를 했던 것에 비해, constexpr 함수는 훨씬 더 직관적인 방법을 제공할 수 있다.

위 예제에 피보나치까지 살짝 추가해, 조금 더 비교해 보면 기존 코드를 죄다 다시 작성하고 싶어질 것이다.

  1. template<unsigned n>
  2. struct Fibonacci
  3. {
  4.     static const unsigned value = Fibonacci<- 1>::value + Fibonacci<- 2>::value;
  5. };
  6.  
  7. template<>
  8. struct Fibonacci<0>
  9. {
  10.     static const unsigned value = 0;
  11. };
  12.  
  13. template<>
  14. struct Fibonacci<1>
  15. {
  16.     static const unsigned value = 1;
  17. };
  18.  
  19. int main()
  20. {
  21.     return Fibonacci<5>::value;  
  22. }
  23.  
  24. ///////////////////////////////////////////////////////////////////////////////////////////////

  25. constexpr unsigned fibonacci(const unsigned x)
  26. {
  27.     return x <= 1 ? 1 : fibonacci(- 1) + fibonacci(- 2);
  28. }
  29.  
  30. int main()
  31. {
  32.     return fibonacci(5);
  33. }


출처 : http://egloos.zum.com/sweeper/v/3147813

728x90

'Basic Programming > C++ 11' 카테고리의 다른 글

c++11 - atomic  (2) 2022.10.13
C++11 - Mordern C++ 프로그래머를 위한 C++ 11/14 핵심  (0) 2018.10.17
C++11 - final, override 키워드  (0) 2017.09.18
C++11 - std::thread  (0) 2016.12.02
C++11 - "default" and "delete" keyword  (0) 2016.11.29
728x90

C#에 보면 #region 이라는 전처리기 지시문이 있다.

이를 사용하면 코드 편집기의 개요 표시 및 숨기기 기능으로 확장하거나 축소할 수 있는 코드 블록을 지정할 수 있다.


이를 Native C++에서도 사용할 수 있다.

이미 자주 사용하고 있는 #pragma 란 전처리기 지시문을 사용하여 할 수 있는데

#pragma region 문자열

#pragma endregion


그런데 이 #pragma 지시어가 이것을 지원하지 않는 다른 컴파일러에서 에러 또는 경고 메시지를 수반하지 않고서 #pragma 지시를 무시하도록 되어 있다고 하는데 어떤 사람은 gcc를 사용하는데 MS VC++로 된 파일을 컴파일 하는데 이 #pragma region 때문에 경고가 발생한다는 이야기를 본 적이 있다.



출처 : http://1and0.tistory.com/47

728x90

'Basic Programming > C, C++' 카테고리의 다른 글

C++ - OutputDebugString()을 편하게 사용  (0) 2019.12.05
C++ - 덤프 파일을 통한 사후 디버깅  (0) 2018.11.21
C++ - Joystick 입력 받기.  (0) 2018.02.01
C++ - inline의 이해  (0) 2017.12.10
C++ - deprecated 키워드  (0) 2017.09.15
728x90

애트리뷰트는 클래스에 메타데이터를 추가할수 있도록 제공한다.

주석과는 달리 클래스부터 시작해서 메소드구조체생성자프로퍼티필드이벤트인터페이스 등 여러가지 요소에 애트리뷰트를 사용할 수 있다.

 

우리가 필요에 의해서 이 애트리뷰트를 사용해 코드 앞에다 설명을 덧붙일 수도 있다.

애트리뷰트의 기본 형식은 다음과 같다:

1 [attribute(positional_parameter, name_parameter = value, ...)]

여기서 positional_parameter는 위치지정 파라미터라고 해서 반드시 적어야하는 부분으로, " "를 사용하여 작성한다그리고 name_parameter는 명명 파라미터로선택적인 정보이며 = 를 사용해서 값을 기입한다.

이 애트리뷰트는 크게 두가지로 나뉘는데사용자가 정의하는 커스텀 애트리뷰트와 내장되어 있는 공통 애트리뷰트로 나뉜다공통 애트리뷰트의 경우는 추가된 정보가 컴파일 방식에 영향을 줄 수 있는데반대로 커스텀 애트리뷰트는 영향을 주지 못한다.

 

대표적인 공통 애트리뷰트로는

Obsolete, Conditional, DllImport이 있다.


1. Obsolete

함수위에 [Obsolete(“출력하고싶은내용”] 을 걸면,

해당 함수 실행시 경고창이 콘솔에 출력된다.


2. Conditional

함수위에 [Conditional(“조건”] 을 걸고,

코드상에 #define 조건을 선언하면해당 함수가 실행되고해당 정의를 빼버리면 실행되지 않는다.


3.  DllImport

함수위에 [DllImport(“Example.dll”)] 을 걸고 extern 키워드를 이용하여 외부 dll에 정의 되어있는 함수를 사용할수 있다.

Public static extern int MessageBox()

 

이 외에도 많은 종류의 애트리뷰트를 제공한다.

 

유니티에서의 제공하는 커스텀 애트리뷰트로는 다음과 같은 것이 있다:


1) AddComponentMenu

기본적으로 스크립트는 유니티의 Component->Scripts 메뉴에 자동추가된다자동추가말고 아무데나 맘대로 넣고 싶으면 AddComponentMenu를 사용한다


2)  ContextMenu

스크립트를 우클릭시 뜨는 context menu에 커맨드를 추가할 수 있다


3) ExecuteInEditMode 기본적으로 play mode일 때만 스크립트가 실행되나 attribute를 사용하면edit mode일 때도 스크립트가 실행되게 한다.

 

4) HideInInspector

inspector에서 안보이게 한다.

 

5) NonSerialized

앞서 HideInInspector는 값을 유지하지만이건 그냥 리셋하여 디폴트값 으로 바꾼다


6) RPC

원격 컴퓨터의 해당 함수를 호출하는 것을 가능케 하는 애트리뷰트다. Remote Procedure Calls라고도 부르며,  유니티 5.1부터는 사용하지 않는 애트리뷰트이다.

 

7) RequireComponent 

함께 필요한 다른 컴포넌트가 자동으로 추가된다.

 

8) Serializable

직렬화 하여 유니티에서 해당 클래스의 내용물이 Inspector에서 보일 수 있도록 한다.


9) SerializeField

private필드를 강제로 serialize한다그러므로 inspector에서도 편집이 가능해진다.




출처 : https://blog.naver.com/captainj/221102947400


728x90

'Basic Programming > C#' 카테고리의 다른 글

C# - 작업 스케줄러에 등록하기  (0) 2021.12.10
C# - Steam Game 실행하기  (0) 2020.07.21
C# - Dispose  (0) 2018.10.12
C# - WeakReference  (0) 2018.10.11
C# - 공부하기 좋은 사이트  (0) 2018.09.05
728x90
  • Make a new C++ project
  • Default options for everything
  • Once created, right-click the project and go to "Properties"
  • C/C++ Build -> Settings -> Tool Settings -> GCC C++ Compiler -> Miscellaneous -> Other Flags. Put -std=c++0x (or for newer compiler version -std=c++11 at the end . ... instead of GCC C++ Compiler I have also Cygwin compiler
  • C/C++ General -> Paths and Symbols -> Symbols -> GNU C++. Click "Add..." and paste __GXX_EXPERIMENTAL_CXX0X__ (ensure to append and prepend two underscores) into "Name" and leave "Value" blank.
  • Hit Apply, do whatever it asks you to do, then hit OK.


출처 : https://stackoverflow.com/questions/9131763/eclipse-cdt-c11-c0x-support


728x90

+ Recent posts