Windows의 MultiByteToWideChar/WideCharToMultiByte 용법과 wchar_t, CP_ACP의 의미

MultiByteToWideChar/WideCharToMultiByte 함수는 여기저기서 많이 쓰던 함수이다. MSDN을 보고 사용 코드를 짜보기도 하고 (이 블로그 옛날 글에도 있다.) 나중에는 귀찮으니 인터넷에 있는거 후려다 쓰기도 했다. 용법은 인터넷에 많이 있으니 패스하고 해당 함수를 사용하면서 언제나 헷갈리는 점이 있는데, 파라메터중 코드페이지 이다.

결론 부터 말하면 두 함수의 첫번째 인자인 코드페이지의 의미가 서로 다르다.
MultiByteToWideChar는 변환하려는 멀티바이트의 코드페이지를 의미한다. 즉 코드페이지에 해당하는 멀티바이트가 들어가서 와이트캐릭터로 나온다.
WideCharToMultiByte는 결과로 나오는 멀티바이트의 코드페이지를 의미한다. 즉 와이드캐릭터가 들어가서 코드페이지에 해당하는 멀티바이트로 나온다.

와이드캐릭터의 입력이나 출력에 코드페이지나 인코딩 형태를 입력하지 않는것을 보면 Windows의 와이드캐릭터는 코드 페이지가 존재하지 않는다는 의미이다. 2바이트 캐릭터라고 해도 인코딩 방식은 여러가지 일텐데 왜 코드페이지가 없는가? C++에서 wchar_t는 2바이트 캐릭터타입이라는 의미이지 특정 인코딩이나 코드페이지를 의미하는것이 아니다.

Windows의 관련 인터넷을 뒤져보니 UTF16 고정인듯 한다. (BE, LE중 뭔지도 좀 구분해서 써주지)
1. https://docs.microsoft.com/en-us/windows/win32/learnwin32/working-with-strings
2. https://docs.microsoft.com/ko-kr/cpp/standard-library/filesystem?view=vs-2019

그리고 위 함수의 인자인 코드페이지 가장 많이 사용하는 값인 CP_ACP.
일반적으로 asni 라고도 하는데, 실제로는 실행되고 있는 윈도우(OS)의 디폴트 코드페이지를 의미한다. 즉 국가별로 CP_ACP는 다른 코드페이지 이다.

그래서 중국 윈도우에서 실행된 클라이언트에서 입력한 멀티바이트 문자열을 한국(OS) 서버에서 MultiByteToWideChar 함수에 CP_ACP로 지정해서 변환하면 깨진다.

오랜 기간 C++을 했지만 문자열 인코딩에 대해서 생각이란걸 해보게 된건 최근이다. 그 전에는 이렇게 해보고 ‘아 안되네?’ 다른 값 넣어보고 ‘음 되네’. OS가 바뀌면 되던게 안되기도 하고 그랬다.

약간 다른 문제이지만… 요즘엔 회사에서 Perforce를 쓰는데 소스 코드든 설정 파일이든 그냥 넣은대로 나왔으면 좋겠는데, 내려받을때 다시 인코딩을 변환해서 골때린다.

C++11의 random 성능 및 distrition 객체의 사용시 마다 생성 문제

c++11의 random 객체의 일반적인 예제를 보면 uniform_int_distribution 객체를 사용하는것이 보이는데
랜덤 변수 하나를 뽑을 때마다 해당 객체를 생성하는 형태로 만들어져 있다.

정말 저래도 괜찮은 걸까..? 테스트를 해봤음.

C의
rand() % 100 + 100

C++의

uniform_int_distribution<int> distribution(100, 199);
distribution(_generator);

코드를 첨부하긴 귀찮고.. 하여간 해봤을때

visual studio 2019에서 디버그 모드는 c++11의 코드가 느렸지만
릴리즈 모드는 서너빼 빠름

신박..

distribution 의 초기화 문제뿐 아니라 랜덤넘버 생성도 c++11은
mersenne_twister 를 쓰는데 우째 더 빠르지..

auto 변수는 레퍼런스 속성을 삭제한다.

아래 코드에서 보듯이 레퍼런스 속성이 삭제됨
그 외 const, volatile 속성 삭제
해당 속성을 유지 하고 싶다면 auto& 를 명확하게 써야한다.

#include <iostream>
using namespace std;

int main()
{
    int a = 10;
    int& b = a;
    auto c = b;
    c = 20;
    cout << a << ", " << b << ", " << c << endl;
    return 0;
}

10,10,20 출력

tuple 구현

#include <iostream>
#include <type_traits>
#include <typeinfo>
using namespace std;
template<typename … Types>
struct xtuple
{
    static constexpr int Size = 0;
};

template<typename T, typename … Types>
struct xtuple<T, Types …> : xtuple<Types …>
{
    T value;
    static constexpr int Size = xtuple<Types …>::Size + 1;
    xtuple() = default;
    xtuple(const T& t, Types … args) : value(t), xtuple<Types …>(args …) {}
};

template<int N, typename T> struct xtuple_get
{
};

template<typename T, typename … Types>
struct xtuple_get<0, xtuple<T, Types …>>
{
    using VT = T;
    using TT = xtuple<T, Types …>;
};

template<int N, typename T, typename … Types>
struct xtuple_get<N, xtuple<T, Types …>>
{
    using VT = typename xtuple_get<N – 1, xtuple<Types …>>::VT;
    using TT = typename xtuple_get<N – 1, xtuple<Types …>>::TT;
};

template<int N, typename T, typename … Types>
typename xtuple_get<N, xtuple<T, Types …>>::VT xget(xtuple<T, Types …>& xt)
{
    using TT = typename xtuple_get<N, xtuple<T, Types …>>::TT;
    return static_cast<TT&>(xt).value;
}

int main()
{
    int v0 = 10101;
    xtuple<int> a(1);
    xtuple<int, short, double> b(v0,2,3.4);
    cout << xget<0>(b) << endl;
    cout << xget<1>(b) << endl;
    cout << xget<2>(b) << endl;
}

C# 스타일의 format 출력

회사에서 Log관련 모듈을 만들어야 하는데
너무 괴로워서 다른 문서를 살펴보다가 va_list, va_arg 같은걸 보고, 일은 하기 싫고 코딩을 안하면 불안하고 해서 만들어 봤음… (생산성 0%…?)


GeSHi © 2004, Nigel McNie



  1. #include <stdio.h>


  2. #include <string.h>


  3. #include <stdarg.h>


  4. #include <stdlib.h>


  5.  


  6. int csharpStyleFormat(const char *format, …)


  7. {


  8.         int extractIdx = -1;


  9.         int argArray[256];


  10.         char buf[1024] = {0,};


  11.         int offset = 0;


  12.  


  13.         va_list ap;


  14.         va_start(ap, format);


  15.  


  16.         const char *cpst = format;


  17.         const char *st = format -1;


  18.         const char *end = NULL;


  19.  


  20.         while (st = strchr(st+1, ‘{‘), st) {


  21.                 char tmpBuf[256] = {0,};


  22.  


  23.                 end = strchr(st+1, ‘}’);


  24.                 memcpy(tmpBuf, st+1, end-(st+1));


  25.                 int index = atoi(tmpBuf);


  26.  


  27.                 while (index > extractIdx) {


  28.                         argArray[++extractIdx] = va_arg(ap, int);


  29.                 }


  30.  


  31.                 int length = (int)(st – cpst);


  32.                 memcpy(buf+offset, cpst, length);


  33.                 offset += length;


  34.                 offset += sprintf(buf+offset, “%d”, argArray[index]);


  35.  


  36.                 cpst = end + 1;


  37.         }


  38.  


  39.         int length = strlen(cpst);


  40.         memcpy(buf+offset, cpst, length);


  41.  


  42.         va_end(ap);


  43.  


  44.         printf(buf);


  45.         return 0;


  46. }


  47.  


  48.  


  49. int main()


  50. {


  51.         csharpStyleFormat(“{2} = {0} + {1}\n, 10, 20, 10+20);


  52.         return 0;


  53. }

Parsed in 0.047 seconds

코드는 이렇다.

csharpStyleFormat(“{2} = {0} + {1}\n”, 10, 20, 10+20);
라고 코드에 쓰면
30 = 10 + 20
이라고 출력됨.

변수타입은 오로지 int만 되는데 {2:d} 이런식으로 변수형을 지정하게 하면 다른 변수들도 가능할듯.
하지만 귀찮..

코드는 에러처리, 최적화는 생각도 하지 않았음…

아 가슴이 답답해…

Effective STL 정리

효과적인 콘테이너 요리법



  • EffectiveSTL01 – 적재적소에 알맞은 컨테이너를 사용하자
  • EffectiveSTL02 – 컨테이너에 독립적인 코드라는 환상을 조심하자
  • EffectiveSTL03 – 복사(copy)는 컨테이너 안의 객체에 맞게 비용은 최소화하며, 동적은 정확하게 하자
  • EffectiveSTL04 – size()의 결과를 0과 비교할 생각이라면 차라리 empty를 호출하자
  • EffectiveSTL05 – 단일요소를 단위로 동작하는 멤버함수보다 요소의 범위를 단위로 동작하는 멤버함수가 더 낫다.
  • EffectiveSTL06 – C++ 컴파일러의 어이없는 분석결과를 조심하자
  • EffectiveSTL07 – new로 생성한 포인터의 컨테이너를 사용할 때에는 컨테이너가 소멸되기 전에 delete하는 일을 잊지 말자
  • EffectiveSTL08 – auto_ptr의 컨테이너는 절대로 만들지 말자.
  • EffectiveSTL09 – 데이타를 삭제할 때에도 조심스럽게 선택할것이 많다.
  • EffectiveSTL12 – STL 컨테이너가 쓰레드 안정성에 대한 기대는 현실에 맞추어 가자.

vector 와 string



  • EffectiveSTL13 – 동적으로 할당한 배열보다는 vector와 string이 낫다.
  • EffectiveSTL14 – reserve는 필요 없이 메모리가 재할당되는 것을 막아 주다.
  • EffectiveSTL15 – 잊지말자 string 은 여러 가지 방식으로 구현되어 있다는 사실을…
  • EffectiveSTL16 – 기존의 C API에 vector와 string을 넘기는 방법을 알아두자
  • EffectiveSTL17 – 쓸데없이 남은 용량은 “바꿔치기(swap)묘수”를 써서 업애 버리자
  • EffectiveSTL18 – vector<bool> 보기를 돌같이 하자

STL 연관 컨테이너



  • EffectiveSTL19 – 상등관계와 동등관계의 차이를 파악하자
  • EffectiveSTL20 – 포인터를 저장하는 연관컨테이너에 대해서는 적합한 비교(비교 함수자) 타입을 정해주자
  • EffectiveSTL21 – 연관컨테이너용 비교 함수는 같은 값에 대해 false를 반환해야 한다.
  • EffectiveSTL22 – set과 multiset에 저장된 데이터 요소에 대해 키(key)를 바꾸는 일은 피하자
  • EffectiveSTL23 – 연관 컨테이너 대신에 정렬된 vector를 쓰는 것이 좋을 때가 있다.
  • EffectiveSTL24 – map::operator[] 나 map::insert는 효율 문제에 주의하여 선택하자.
  • EffectiveSTL25 – 현재는 표준이 아니지만, 해쉬 컨테이너에 대해 충분히 대비해 두자.

반복자



  • EffectiveSTL26 – const_iterator 나 reverse_iterator, const_reverse_itertor도 좋지만 역시 쓸만한 것은 iterator 이다.
  • EffectiveSTL27 – const_iterator를 iterator로 바꾸는 데에는 distance와 advance를 사용하자.
  • EffectiveSTL28 – reverse_iterator에 대응되는 기점 반복자(base iterator)를 사용하는 방법을 정확하게 이해하자.
  • EffectiveSTL29 – 문자 단위의 입력에는 istreambuf_iterator의 사용도 적절하다.

알고리즘



  • EffectiveSTL30 – 알고리즘의 데이타 기록 범위는 충분히 크게 잡자.
  • EffectiveSTL31 – 정렬시의 선택 사항들을 제대로 파악해보자.
  • EffectiveSTL32 – 요소를 정말로 제거하고자 한다면 remove 류의 알고리즘에는 꼭 erase를 붙여 사용하자.
  • EffectiveSTL33 – remove와 비슷한 알고리즘을 포인터의 컨테이너에 적용할 때에는 각별히 조심하자.
  • EffectiveSTL34 – 정렬된 범위에 대해 동작하는 알고리즘이 어떤 것들인지 파악해 두자.
  • EffectiveSTL35 – 대소문자를 구분하지 않는 문자열 비교는 mismatch 아니면 lexicographical_compare를 써서 간단하게 구현할 수 있다.
  • EffectiveSTL36 – copy_if를 적절히 구현해 사용하자.
  • EffectiveSTL37 – 범위 내의 데이터 값을 요약하거나 더하는 데에는 accumulate 나 for_each를 사용하자.

함수자, 함수 객체, 함수, 기타 등등



  • EffectiveSTL38 – 함수자 클래스는 값으로 전달되도록 설계하자.
  • EffectiveSTL39 – 술어 구문은 순수 함수로 만들자.
  • EffectiveSTL40 – 함수자 클래스는 어댑터 적용이 가능하게(adaptable) 만들자.
  • EffectiveSTL41 – ptr_fun, mem_fun, mem_fun_ref 의 존재에는 분명한 이유가 있다.
  • EffectiveSTL42 – less<T>는 operator< 의 의미임을 꼭 알아두자.

STL 프로그래밍을 더 재미있게 해주는 팁 모음



  • EffectiveSTL43 – 어설프게 손으로 작성한 루프보다 알고리즘이 더 낫다.
  • EffectiveSTL44 – 같은 이름을 가진 것이 있다면 일반 알고리즘 함수보다 멤버 함수가 더 낫다.
  • EffectiveSTL45 – count, find, binary_search, lower_bound, upper_bound, 그리고 equal_range 를 제대로 파악해 두자.
  • EffectiveSTL46 – 알고리즘의 매개 변수로는 함수 대신 함수 객체가 괜찮다.
  • EffectiveSTL48 – 용도에 맞는 헤더를 항상 #include 하자
  • EffectiveSTL50 – STL 관련 웹 사이트와 친구하자

STL 관련 웹 사이트와 친구하자


SGI STL 사이트 #

[http]http://www.sgi.com/tech/stl/
STL 컴포넌트에 관해서 종합적으로 설명을 해놓았으며 온라인 참고 메뉴열이 존재한다.
또한 비표준 STL 컴포넌트도 제공하고 있다.

  • 헤쉬 연관 컨테이너
  • 단일 연결 리스트 컨테이너
  • 매우 긴 문자열을 담을수 있는 string 류의 컨테이너 : rope
  • 다양한 비표준 함수자 객체와 어댑터들 : select1st, select2nd, identity, project1st …
자세한 내용은 책이나 웹사이트를 참고하자.

STLport 사이트 #

[http]http://www.stlport.org/
여러가지 플렛폼에서 동작하는 STL 소스를 얻을수 있다.
특징은 SGI를 기반으로 만들어져 폭넓게 사용가능 하다는 점과 독특한 디버그 모드를 제공한다는 점이다.
자세한 예는 책을 참조하자.

Boost 사이트 #

[http]http://www.boost.org/
표준은 아니지만 곧 표준이 될만한 내용들을 담고 있는 라이브러리를 제공한다. STL을 기반으로(?) 다양한 기능을 지닌 컴포넌트들을 제공한다.

용도에 맞는 헤더를 항상 #include 하자

플렛폼마다 헤더파일의 인클루드 의존이 약간식 다를수 있다. 그러니 필요한 모든 헤더파일을 인클루드해 놓는 습관을 들여야 다른 플렛폼으로 갔을때 삽질을 피할수 있다.



  • 거의 모든 컨테이너들은 동일한 이름의 헤더에 정의되어 있다. 하지만 multiset 과 multimap은 각각 <set>, <map>에 정의 되어있다.
  • 네 개를 제외한 모든 알고리즘은 <algorithm> 에 정의되어 있다. 제외된 accumulate, inner_product, adjacent_differnce, partial_sum 은 <numeric>에 정의되이 있다.
  • istream_iterator와 istreambuf_iterator를 포함한 특별한 종류의 반복자는 <iterator>에 선언되어 있다.
  • 표준 함수자(less<T>) 함수자 어뎁터(not1, bind2nd 등)은 <functional> 에 정의되어 있다.

알고리즘의 매개 변수로는 함수 대신 함수 객체가 괜찮다.

사실 이건 함수객체가 엄청난 기능이 있어서라기 보다 컴파일 타임에 코드가 구성 되는 템플릿의 특성에 기인한 것이다.즉 함수 포인터를 넘기는 경우 동일한 인자를 가진 함수들을 교체가 가능하지만 포인터로서 사용함으로써 한번의 참조가 더 일어나게 된다.

하지만 여기서 언급하는 함수객체는 STL의 대부분의 알고리즘이나 함수들이 템플릿 프로그래밍 되어 있으므로 함수객체를 코딩하고 알고리즘에 함수객체를 컴파일 타임에 결정해 줌으로써 템플릿 확장이 일어나 최적화가 되는 것이다. 마치 인라인 확장과 동일 내용이다.

물론 함수 포인터의 경우도 컴파일 타임에 분석해서 최적화를 할수 있을지 모르겠지만 현재의 컴파일러 대부분이 지원하지 않는다고 한다.

그리고 함수객체를 사용하면 컴파일러 마다 서로 약간씩 다르거나 버그 스러운 면을 자연스로럽게 비껴갈수 있다. 자세한 내용은 책을 참조하자.