728x90

어셈블리언어에는 특정 코드 위치로 바로 이동하기 위해서 goto 키워드를 많이 사용한다.
C언어에서도 goto 키워드가 존재하지만 절차식의 C 프로그래밍을 배우면서
흐름을 깨기 때문에 사용하지 않기를 권장한다.

유닉스를 만들기 위해 개발한 언어가 C인데, 정작 유닉스 & 리눅스 코드에서는
goto 키워들 상당 부분에서 발견할 수 있다.
간단히 말해서 엉키지 않게 제대로만 쓰면 error 처리하는 용도로 편리하게 이용할 수 있다.
다시 말하면 함수의 알고리즘의 흐름 상에서 다수의 error 검출을 해서 주로 공통적인 error 처리를 하는 경우,
함수의 끝에 error를 위한 특정 코드를 추가하고 Label을 설정해서 goto 키워드를 이용하는 방식이다.

이러한 goto 대신 비슷하게 사용할 수 있는 방식이 do while을 이용하는 것이다.

do{
  if (err)
      break;
}while(0);
error_handling_code

위와 같은 방식으로 while() 안에 조건을 '0'으로 하여 한 번만 실행되게 하고,
블록 안에서 error가 발생한 경우에만 블록을 빠져나오게 하여 while 이후의 코드를 실행하게 하는 것이다.

본인이 생각컨대 goto 키워드를 굳이 써서 다른 기능을 구현하자면,
다수의 Error에 대해서 그 처리가 공통적이지 않은 경우 여러 개의 Label과
해당 Label로 이동하게 하는 goto 키워드를 써서 구현하는 것이다.
이 경우 절차식 처리에서 상당히 벗어나는 어셈블리언어식 코드가 되는데
엉키지 않도록 주의해서 사용해야 할 것이다.

쓸데 없는 얘기를 많이 한 것 같은데,
결론적으로 goto 키워드를 통한 error 처리 대신에 do while(0)을 쓸 수 있다는 것을 알아두자는 것이다. ^^;


출처 : http://neodelicious.tistory.com/46



goto문에 대한 논의 : https://kldp.org/node/40440

728x90
728x90

리눅스 커널 소스를 살펴보다가 헤더쪽의 매크로에서 “do { … } while(0)” 와 같은 것이 많이 쓰인 것을 보았다.
당연히 { … } 이 한번만 실행되고 끝나는 건데, 왜 이렇게 했을까 궁금해서 찾아보았다.

정리하자면,

1. 빈 문장(“;”)은 컴파일러에서 Warning 을 발생시키므로 이를 방지!
2. 지역변수를 할당할 수 있는 Basic block 을 쓸 수 있다.
3. 조건문에서 복잡한 문장을 사용할 수 있다. 예를 들면 다음과 같은 코드가 있다고 했을 때,

#define FOO(x) \
        printf(“arg is %s\n”, x); \
        do_something_useful(x);


다음과 같이 이 매크로를 사용한다면,

if (blah == 2)
        FOO(blah);


이렇게 해석되어서 쓰여진다.

if (blah == 2)
        printf(“arg is %s\n”, blah);
        do_something_useful(blah);;


뭐가 문제냐고? do_something_useful(blah); 는 조건에 관계없이 수행된다. 이는 원하는 결과가 아니다. 하지만 do { … } while(0) 를 쓴다면 다음과 같이 해석될 것이다.

if (blah == 2)
        do {
                printf(“arg is %s\n”, blah);
                do_something_useful(blah);
        } while (0);


정확히 원하는 결과를 얻을 수 있다.

4. 3번과 같은 경우에 다음과 같이 사용할 수도 있지 않냐고 생각할 수 있다.

#define exch(x,y) { int tmp; tmp=x; x=y; y=tmp; }


그러나 다음과 같은 경우에는 원하는데로 동작하지 않는다.

if (x > y)
        exch(x,y);          // Branch 1
else  
        do_something();     // Branch 2


왜냐하면 다음과 같이 해석되기 때문이다.

if (x > y) {                // Single-branch if-statement!!!
        int tmp;            // The one and only branch consists
        tmp = x;            // of the block.
        x = y;
        y = tmp;
}
;                           // empty statement
else                        // ERROR!!! “parse error before else”
        do_something();


do { … } while(0) 를 사용하면 다음과 같이 해석되어 원하는 의도대로 정확히 쓸 수 있다.

if (x > y)
        do {
                int tmp;
                tmp = x;
                x = y;
                y = tmp;
        } while(0);
else
        do_something();


5. gcc에서는 Statements and Declarations in Expressions 확장을 사용할 수 있다. 이는 위에서 본 do-while-0 Block 대신 쓸 수 있다.



출처 : http://blog.dasomoli.org/220/

728x90
728x90
C++에서 싱글톤 구현하기
; http://agbird.egloos.com/<wbr />4730538


일단, 위의 글과 함께 댓글들을 읽어보면서 한가지 놀란 점이 있습니다. 의외로 "Thread-Safe"하냐는 것에 대해서는 아무도 관심을 갖고 있지 않았기 때문입니다.


알려진 바에 의하면, 초기화 순서가 불분명하다는 단점에도 불구하고 Singleton 과 같이 구현하는 경우에는 Thread-safe합니다. 하지만, 겉으로 좋아보이는 DynamicSingleton 의 경우에는 Thread-safe하지 않다는 다소 치명적인 단점이 있습니다.


이 문제를 해결하는 것이 생각보다 만만치 않은데 아래의 문서에서 아주 자세히 설명해 주고 있습니다.


C++ and the Perils of Double-Checked Locking
; http://www.aristeia.com/<wbr />Papers/DDJ_Jul_Aug_2004_<wbr />revised.pdf


DynamicSingleton 을 위의 문서대로 thread-safe하게 다시 구현해 볼까요? ^^


우선, 잠금을 통해서 Thread-safe하게 바꿉니다.


class DynamicSingleton {
  private:
  ... [생략] ...
  public:
    static DynamicSingleton* getInstance() 
    {
      Lock lock;
      if (inst == 0) inst = new DynamicSingleton();
      return inst;
    }
};


하지만, 매번 getInstance 때마다 쓰레드 경합이 발생할 여지를 두는 것은 좋지 않기 때문에 다음과 같이 DCLP(Double Chceked Locking Pattern)을 이용해서 개선할 수 있습니다.


static DynamicSingleton* getInstance() 
{
  if (inst == 0)
  {
    Lock lock;
    if (inst == 0) 
    {
      inst = new DynamicSingleton();
    }
    return inst;
  }
}


그래도 여전히 헛점이 있습니다. 명령어 재배열과 같은 최적화 기법에 의해 inst = new DynamicSingleton 이라는 구문에 오류를 발생할 수 있는 여지가 존재하게 됩니다. 즉, 생성자가 불리지 않았음에도 불구하고 inst 변수에 값이 할당되어져 있는 상황이 발생하게 되고 연이은 쓰레드의 호출에서 생성자가 호출되지 않는 상태의 그 inst 변수가 사용되어져 버리는 것입니다. 그래서 다음과 같이 바뀌어야 합니다.


class DynamicSingleton
{
private:
    static volatile DynamicSingleton* volatile inst;

    static volatile DynamicSingleton* volatile getInstance() 
    {
      if (inst == 0)
      {
        Lock lock;
        if (inst == 0) 
        {
          volatile DynamicSingleton* volatile temp = new volatile DynamicSingleton;
          inst = temp;
        }
        return inst;
      }
    }
}


위와 같이 volatile 로 하는 경우 말고도 다중 프로세서에서의 메모리 캐쉬 문제를 해결하기 위해 Memory Barrier를 직접 사용하는 방법을 택하는 것도 가능합니다. 그래서... 다음과 같이 구현해도 됩니다.


#include <intrin.h>
#pragma intrinsic(_ReadWriteBarrier)

class DynamicSingleton
{
private:
    static DynamicSingleton* inst;

    static DynamicSingleton* getInstance() 
    {
      DynamicSingleton* volatile temp = inst;
      _ReadWriteBarrier();
      if (temp == 0)
      {
        Lock lock;
        temp = inst;
        if (temp == 0) 
        {
          temp = new DynamicSingleton;
          _ReadWriteBarrier();
          inst = temp;
        }
        return inst;
      }
    }
}


PhoenixSingleton 은, 바로 위의 코드와 같이 Thread-safe 문제를 어느 정도 해결한 상태에서 살을 붙여야 할테니... "C/C++ 에서 thread-safe 한 Singleton 개체"를 사용하는 것이 그다지 녹록치만은 않습니다. (사실 이것은 C/C++ 만의 문제는 아닙니다.)


위의 PDF 문서에 의하면, (학문적으로 파고들기에는 제가 실력이 모자라서 이해하기 힘들지만) C++의 abstract machine 자체가 단일 쓰레드이기 때문에 위와 같은 소스 코드의 보정에도 불구하고 thread-unsafe한 기계어를 생산하는 C++ 컴파일러도 있다고 합니다. VC++이 그런 경우에 포함되는 것인지는 확인할 길이 없고. (이런 거 보면... 저도 어쩔 수 없는 "응용 개발자"에 속해 있지요. ^^ 그래서 가끔 이런 것들을 학문적으로 파헤치는 분들이 부러울 때가 있습니다.)


그나 저나, abstract machine 이 다중 쓰레드인 언어는 그럼 또 뭐가 있는 건가요?




참고로, "C++에서 싱글톤 구현하기"에서 소개된 코드 중에 "명시적인 해제 작업을 피하기 위해서는 static 지역 객체를 사용하면 됩니다" 라면서 소개한 코드가 있는데요. 그것 역시 Thread-safe 하지 않다는 문제가 있습니다. 이에 대해서는 다음의 글에서 설명되어져 있습니다.


C++ scoped static initialization is not thread-safe, on purpose!
; http://blogs.msdn.com/<wbr />oldnewthing/archive/2004/03/<wbr />08/85901.aspx


재미있게도, scoped-static 초기화가 C++ 표준에 의해서 구현되었기 때문에 thread-safe하지 않은 것이 일단은 당연하다고 되어 있는데 댓글들을 보면 C++ 표준이 아닌 마이크로소프트 임의 구현이라는 비난이 있습니다.

표준이든 아니든, VC++은 일단 그렇게 구현되어 있기 때문에 주의하는 것이 좋겠습니다. ^^
(그런데, 위의 글이 2004년도에 씌여진 것이라서 VC++ 10 에서는 어떻게 바뀌었을지... 모를 일이군요)



끝으로. 한가지 더!

만약 저한테 Thread-safe한 C/C++ 코드를 만들라고 하면.
차라리 주 Thread-safe 개체와 그에 종속된 Thread-safe 한 개체를 만들도록 기본 방침을 정할 것 같습니다. 무슨 소리냐면. 전역적인 static 초기화가 Thread-safe함에도 불구하고 그 순서를 알 수 없다는 이유로 때로 사용이 기피되는데 이것만이 그 이유라면 다음과 같은 식으로 해결할 수 있다는 것입니다.

// ThreadSafeSingleton 개체는 전역 static 으로 등록하고.
class ThreadSafeSingleton
{
   ThreadSafeSingleton()
   {
       // 순서 대로!
       SingletonA()->Initialize();
       SingletonB()->Initialize();
       SingletonC()->Initialize();
   }
}


출처 : http://www.sysnet.pe.kr/

728x90
728x90

Windows API 중에 SetLayeredWindowAttributes()를 이용하여 윈도우를 투명하게 바꿀 수 있다.


// make it transparent

long l = GetWindowLong(m_hWnd, WL_EXSTYLE);

l |= WS_EX_LAYERED;

SetWindowLong(m_hWnd, GWL_EXSTYLE, l);

SetLayeredWindowAttributes(m_hWnd, 0, nOpacity, LWA_ALPHA);


이 API를 이용하면, 프레임 드랍이 굉장히 심하다...



그래서 구글에서 검색해본 결과, Windows의 Aero 기능을 활용하는 방법이 있었다.


DWM(Desktop Window Manager)가 실행되어 있어야하므로, 프로세스에 dwm.exe가 실행되어 있어야 한다.


// Set margins, extending the bottom margin

MARGINS margins = { -1, -1, -1, -1 };

int val = 0;    // 2;

hr = DwmSetWindowAttribute(m_hWnd, 2, &val, 4);


// Extend frame on the bottom of client area

hr = DwmExtendFrameIntoClientArea(m_hWnd, &margins);


위의 코드를 활용한다면, Aero 기능을 활용하기 때문에 SetLayeredWindowAttributes() 보다는 쓸만 했다.

728x90
728x90

팩토리 패턴은 기본적으로 2개로 분류(Factory Method, Abstract Factory) 된다.


팩토리 메소드(Factory Method)는 객체를 생성하되 직접 객체의 생성자를 호출해서 객체를 생성하는 것이 아니라 대행 함수를 통해 간접적으로 객체를 생성하는 방식이다.


쉽게 말하면, 스타크래프트에서 배럭(클래스)에서 유닛(추상클래스)를 통해 마린, 파이어뱃, 메딕 등을 생성하게 된다.


소스코드


unit.h




barracks.h




main.cpp



위와 같이 배럭(클래스)에서는 상황에 따라 마린 또는 메딕등을 생성하지만 무엇이 생성되었는지는 알지 못해도 생성된 유닛을 사용하는데는 문제가 없다. 이렇듯 Factory에서 생성된 객체를 사용자는 종류에 신경쓰지 않고 생성된 객체를 똑같이 사용할 수 있다.




추상 팩토리(Abstract Factory)는 클래스의 객체를 전담 생성하는 클래스를 두지만, 새로운 제품군 생성을 추가하는 것이 쉽도록 클래스 상속을 도입하고 구체적인 제품군별 Factory 클래스 상위에 Abstract Base Class를 정의한 형태의 설계구조를 말한다.


쉽게 말하면 Factory Method의 확장 버전으로 Unit 뿐만이 아니라 Barracks도 Factory Method화 하는 것이다.




아래의 소스 코드에서 ISword는 Unit, ISwordFactory는 Factory의 추상화라고 생각하고 소스 코드를 보면 될 것 같다.


소스 코드


Sword.h




Factory.h




main.cpp




추상 팩토리 패턴에서 팩토리 클래스들의 각 멤버 함수들은 앞에서 언급한 팩토리 메서드(Factory Method) 패턴 형태로 구현되어 있으며 추상팩토리 패턴은 기본적으로 팩토리 메서드 패턴을 활용해서 구현한다.


단점은 새로운 객체가 추가 될때마다 새로운 팩토리 클래스를 정의하고 구현해야 하는 불편함을 초래하는데 이 부분을 해결하려면 객체를 종류별로 팩토리 클래스에 등록해두고 객체 생성 요청시 복제해주는 방식(프로토타입 패턴)을 사용한다.


또한 팩토리 객체를 하나만 두고 싶을 때는 싱글턴 패턴을 사용하면 된다.






출처 : http://blog.naver.com/sorkelf/40169734025http://egloos.zum.com/ani2life/v/2887675

728x90
728x90

#include <windows.h>

#include <iostream>

#include <tchar.h>


int main()

{

    _wsetlocale(LC_ALL, _T("Korean"));


    wchar_t strText[MAX_PATH] = { 0, };

    HINSTANCE hLanguageDll = nullptr;

    LANGID wLanguageID = 0;


    // OS의 언어 ID를 가져온다.

    wLanguageID = GetUserDefaultUILanguage();

    //wLanguageID = 0x412;    // 한글

    //wLanguageID = 0x409;    // 영어


    switch (wLanguageID)

    {

    case 0x409 :    // 영어

        hLanguageDll = LoadLibrary(_T("Language_Eng"));        

        break;


    case 0x412 :    // 한글

        hLanguageDll = LoadLibrary(_T("Language_Kor"));        

        break;

    }


    if (hLanguageDll == nullptr)

        return -1;


    LoadString(hLanguageDll, 101, strText, MAX_PATH);

    wprintf(L"%s \r\n", strText);


    FreeLibrary(hLanguageDll);


    getchar();

    return 0;

}



LANGID : https://msdn.microsoft.com/ko-kr/library/bb165625(v=vs.90).aspx

Display name

Value

Default charset

Arabic

1025

Arabic

Basque

1069

ANSI

Catalan

1027

ANSI

Chinese (Simplified)

2052

GB2312

Chinese (Traditional)

1028

Chinese-Big 5

Czech

1029

Eastern European

Danish

1030

ANSI

Dutch

1043

ANSI

English (United States)

1033

ANSI

Finnish

1035

ANSI

French

1036

ANSI

German

1031

ANSI

Greek

1032

Greek

Hebrew

1037

Hebrew

Hungarian

1038

Eastern European

Italian

1040

ANSI

Japanese

1041

Shift-JIS

Korean

1042

Johab

Norwegian

1044

ANSI

Polish

1045

Eastern European

Portuguese

2070

ANSI

Portuguese (Brazil)

1046

ANSI

Russian

1049

Russian

Slovakian

1051

Eastern European

Slovenian

1060

Eastern European

Spanish

3082

ANSI

Swedish

1053

ANSI

Turkish

1055

Turkish


참조 : http://copynull.tistory.com/91


StringTable.zip


728x90
728x90

자꾸 DLL 만들 때 마다 검색하게 되는 것 같다. ㅠ


그냥 코드만 정리해서 올려둔다.



#include <windows.h>


#ifdef MYDLL_EXPORTS

#define MYDLL __declspec(dllexport) 

#else

#define MYDLL __declspec(dllimport) 

#endif


BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)

{

switch (ul_reason_for_call)

{

case DLL_PROCESS_ATTACH:

case DLL_THREAD_ATTACH:

case DLL_THREAD_DETACH:

case DLL_PROCESS_DETACH:

break;

}


return TRUE;

}




사용 예제는 그냥 소스 코드를 첨부하겠다...


DllExample.zip


728x90
728x90

현재 윈도우의 정확한 버전을 얻기 위해서는 Network Management 함수 중 하나인 NetWkstaGetInfo() 를 이용하는 것이다.




NetWkstaGetInfo ()가 다소 느리므로, 처음 호출할 때에는 버전을 알아내기 위해 NetWkstaGetInfo ()를 호출하고, 이 후에는 저장된 값으로 확인하는 것이 좋다.



VerifyVersionInfo() 를 이용하면, ServicePack 버전까지 알아낼 수 있다.




출처 : http://iamskylover.tistory.com/75


Source.cpp


728x90

+ Recent posts