최근 포토로그


C++ 배열의 불편한 진실 복잡한컴퓨터이야기

C++에서 배열은 다른 자료형에 비해서 상당히 이질적인 특성을 가지고 있습니다. 배열의 표기(notation)는 특별할 것이 없으나, 내부적으로는 직간접적으로 포인터와 연관성을 매우 많이 가지고 있고, 배열이 가진 타입 정보도 은연중에 소실 되기 때문입니다.

먼저 배열의 선언과 특성에 대해서 몇 가지 살펴 보려고 합니다.

char a[10];

char b[10][20];

각각은 1차원, 2차원 배열인데, 대괄호 [ ] 를 이용하여 1차원 혹은 다차원을 표기할 수 있는 것은 매우 편리하게 보입니다. 여기서 a, b 라는 변수는 배열 전체를 나타내는 변수이기도 하지만, 그 자체로 배열의 첫번째 요소를 가리키는 포인터의 역할을 수행하기도 합니다.

포인터와의 연관성을 살펴보기 위해서 다음과 같은 재미난 시도를 해볼 수 있습니다.

assert (a[5] == 5[a]);

위와 같은 비교 연산이 성립하는 이유는 a[5]를 통해 배열의 개별 요소에 접근할 때, 직접적으로 a에 대한 포인터 연산을 수행하기 때문입니다. 아래를 보면 이해가 되실 것 같습니다.

a[5] = *(a + 5) = *(5 + a) = 5[a]

다른 관점에서, 위 배열들에 대해서 다음과 같이 코드를 작성하여 변수들의 타입정보와 메모리 크기를 살펴보면,


cout << "a[10] is type of "<< typeid(a).name() << ", sizeof()=" << sizeof(a)<< endl;

cout << "b[10][20] is type of" << typeid(b).name() << ", sizeof()=" <<sizeof(b) << endl;

다음과 같은 결과를 얻을 수 있습니다.


a[10] is type of char [10], sizeof()=10

b[10][20] is type of char [10][20],sizeof()=200


이 결과로부터 ab는그 크기와 타입 정보를 명확하게 가지고 있음을 알 수 있지요.


그런데. 그런데

추가적으로 배열에 대해서 좀 더 살펴보겠습니다. 배열을 함수의 인자로 전달하는 경우는 어떨까요?

int sum(char a[10])

{

           cout<< "a[10] is type of " << typeid(a).name() <<", sizeof()=" << sizeof(a) << endl;

           return0;

}

sum(a);
라고 호출하면 어떤 결과가 출력될까요? 결과는 다음과 같습니다.

a[10] is type of char *, sizeof()=4

앞서 출력한 내용과 그 결과가 완전히 그 다름을 알 수 있습니다.
두가지 면에서 크게 놀랄 수 밖에 없는데요, 먼저
a[10] 는 사라지고  a를 char *로 보고 있다는 것입니다.
C/C++은 만일 함수의 매개변수를 다른 타입으로 정의 하였다면,
call by value(pass by value)의 형태로 값이 전달되었을 것입니다.
그런데 배열을 인자로 전달하는 경우는 다른 타입과는 다르게, call by pointer와 유사한 형태로 인자를 전달하며, 그렇다 보니 배열은 call by value시에 발생하는 복사 과정이 이루어지지 않게 됩니다.
더 나쁜 것은 앞서 보신 것과 같이 sum()의 매개변수를 통해 전달 받은 a는 모든 타입 정보를 소실하고 a를 단순히 char * 로만 인지하며, 그 결과 sizeof(a)의 결과 같이 4가 된다는 사실입니다.
우리가 알게 모르게 배열을 인자로 전달할 때에 배열 그 자체와 더불어 배열 요소의 개수를 같이 전달할 수 밖에 었었던 것은, 이처럼 배열로 선언된 변수를 함수로 전달하면, 가지고 있는 타입 정보를 모두 소실 하기 때문입니다.
이는 배열이 C/C++에서 하나의 독립된 타입으로 인정되지 않고 포인터의 또 다른 표현 기법에 지나지 않기 때문입니다.
이로 인해 다음과 같은 문제가 발생합니다.

i
nt sum(char a[10]) {

for (auto &each : a)    // error !!!

           cout<< each;

}

 

int main() {

char a[10];

for (auto &each : a)            

           cout<< each;

sum(a);

}

다차원 배열에 대해서는 테스트 해보시면 직접 테스트 해보시기 바랍니다.
배열의 이러한 문제점을 최소화 하면서도 장점을 최대화 한 것이 바로 std::vector입니다. 이를 사용하면 타입 안정성을 계속해서 유지할 수 있을 뿐 아니라, 가변 배열의 효과도 같이 얻을 수 있을 뿐 아니라, 위와 같이 range-for에 대해서도 아무런 문제가 없이 사용될 수 있습니다.
물론 의미론적으로 바라 볼 때 배열은 std::array와 좀 더 근거리에 있다고 볼 수도 있습니다.

결론적으로, 큰 메모리 블록을 다용도로 사용하는 경우를 제외하고는 std::vectorstd::array를 사용하는 편이 실보다 득이 훨씬~~ 훨씬 많습니다.


C++11 auto와 {}-init-list 의 모호함 복잡한컴퓨터이야기

C++11에는 auto라는 키워드를 통해서 타입추론(deduction)을 수행하도록 기능이 추가 되었습니다. 이제 auto를 사용하면 할당 연산자나 객체 초기화 시에 객체의 타입을 명시적으로 지정하지 않아도 되기 때문에 코드를 간결하게 쓸 수 있습니다. 몇 가지 예를 살펴보시죠.

auto v1 = 10;

auto v2 = ‘c’;

auto v3 { f() };

for (auto &each : v)

           //do something

이것이 가능한 이유는 rValue로부터 타입을 추론할 수 있기 때문에 굳이 객체의 타입을 명시할 필요가 없기 때문이지요. 즉 위의 첫 번째 예를 살펴보면 할당 연산자 우측의 10이 이미 int 타입이기 때문에 v1을 명시적으로 int로 선언하지 않아도 컴파일러가 v1int로 추론할 수 있기 때문입니다.

또한 C++11에서는 {}를이용한 객체 initialize가 가능합니다. 이를 이용하면 다음과 같이 객체를 초기화 할 수 있기 때문에 위 예제 중 2가지를 고쳐 쓸 수 있습니다.

auto v1 {10};

auto v2{ ‘c’ };

 

또한 vector와 같은 container들에 객체를 삽입할 경우에 반복적으로 push_back()을 하는 수고를 덜기 위해서 {}-init-list 라는 기능을 제공하는데요. 간단히 예를 통해서 알아보면

vector<int> v = {1, 2, 3};

list<int> l = {1, 2, 3};

라고 작성할 수 있지요. 이 경우 할당 연산의 우측 { }는 컴파일시에 std::initializer_list<T> 타입으로 해석되며, vector liststd::initializer_list<T> 타입을 매개변수로 취하는 생성자가 호출되게 됩니다.

,

auto v1 = {1,2,3};

이라고 할 경우 v1std::initializer_list<int>타입으로 타입 추론이 수행됩니다. vector<int>list<int>를 사용한 예제는 다음과 같이 {}-init-list를이용하여 다음과 같이 작성할 수도 있습니다.

vector<int> v {1, 2, 3};

list<int> l {1, 2, 3};

만약, 원소가 1개인 vector list를 작성하려면 다음과 같이 작성할 수도 있겠지요.

vector<int> v{1};

list<int> l{1};

 

여기까지 이해가 되셨다면 다음과 같은 예제를 살펴보겠습니다.

 

int v1{ 123 };                 <- 1

auto v2{ 123 };              <- 2

auto v3 = { 123 };          <- 3

auto v4{ 1, 2, 3 };           <- 4

auto v5 = { 1, 2, 3 };       <- 5

 

1은 명확합니다. v1 123 이라는 정수 값을 가지도록 초기화 됩니다.

2는 어떨까요? 약간 애매합니다. 왜냐하면 v2 123이라는한 개의 정수를 가진 initializer_list 컬렉션으로 해석해야 할지 아니면 123이라는 정수 값을 가진 int v2로 해석해야 할지 혼돈스럽습니다.

3의 경우는 어떠할까요? 이또한 명확합니다. v3initializer_list<int>로추론됩니다.

4의 경우는 3의 경우와 마찬가지로 initializer_list<int>로 추론되는 것이 맞을 것 같습니다.

5의 경우도 비교적 명확해 보입니다.이 또한 initializer_list<int>로 추론 될 것입니다.

 

여기서 주의 깊게 살펴 보아야할 것은 2번과 4번입니다.

먼저 C++ 11의 경우라면 2initializer_list<int>로 추론이 이루어지며, 4번 또한 동일합니다. 의미론적으로는 명확해 보입니다. 하지만 개발자의 입장에서는 이것이 보통 혼돈스러운 것이 아닙니다. 아래를 보시죠.

int v1{ 123 };                 <- 1

auto v2{ 123 };              <- 2

auto v5 = { 1, 2, 3 };       <- 5

단지 int auto로 변경했을 뿐인데, 1의 경우는 v1int로 추론하고 123을 할당하였습니다. 하지만 25의 경우는 v2v5initializer_list<int>로해석하여 일종의 collection으로 초기화 합니다.

1 2만 살펴보면, 이 둘은 그 구조가 매우 유사함에도 명시적으로 타입을 지정하느냐 하지 않느냐에 따라 혼돈스럽게 동작합니다. 게다가 다음과 같은 MyType이 정의되어 있다고 가정해 봅시다.

class MyType {

public:

           int_x, int _y;

           MyType(intx, int y) : _x{ x }, _y{ y } {}

};

 

이 경우 MyType 객체를 생성하기 위해서 다음과 같이 코드를 작성할수 있습니다.

MyType v3{1, 2};

MyType 2개의 정수값을 취하는 생성자를 가지고 있기 때문에 위 코드는 MyType 형 객체를 생성하고 _x, _y를 각각 1,2로 초기화 합니다. 이제는 더욱 혼란스럽습니다.

이러한 혼란을 정리하고자 Bjarne Stroustrup auto{}-init-list를 동시에 사용할 경우에는 모호함을피하기 위해서 반드시 할당 연산을 이용하라고 말하고 있습니다.

auto v2 = {123};

auto v5 = {1, 2, 3};

으로만 사용할 것을 권고 한다는 것이죠.

여러분은 어떻게 생각하실지 모르지만, 마이크로소프트의 일부 개발자들은 이러한 문법적 모호성을 개선할 필요가 있다고 느낀 것 같습니다. 이에 지난 6C++ WG21standard meeting을 통해서 N3922(http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2014/n3922.html)를 제안하였으며, 11월에 있을 다음 standard meeting에서채택 여부를 결정하기로 하였다고 합니다. (이렇게 결정된 내용은 아마도 C++14에 반영될 것 같습니다.) N3922의 내용을 간단히 살펴보면, auto에 직접 붙여서 {}-init-list를 사용하는 경우는element를 하나만 쓸 수 있게 한다. 동시에 이 경우는 list가 아니라 객체 초기화로 간주한다. 입니다. 이게 무슨 말인고 하니,

auto v2{ 123 };              <- 2

와 같은 문장을 기존에는 123이라는 한 개의 요소를 가진 initializer_list<int>로 추론하였으나 이제는 그렇게 하지 않고 정수 타입으로 추론한다는것입니다. 그리고

auto v4{ 1, 2, 3 };           <- 4

와 같은 문장은 허용하지 않을 것이며, 반드시 이렇게 초기화를 해야한다면

auto v4 = {1, 2, 3};

과 같이 초기화 해야 한다는 것이지요.

제가 알고 있는 한도 내에서는 N3922가 반영되어 있는 유일한 컴파일러는Visual Studio 14 CTP3/4 이며 VisualStudio 2013 Update 3GCCN3922를반영하지 않았습니다. (당연합니다. 아직 표준으로 받아들여지지 않았으니까요.)

여러분은 어떤 것이 더 직관적이고 올바른 문법 규정이라고 생각하시나요? 저는개인적으로 N3922가 반드시 받아들여 졌으면 좋겠습니다.

 


이전, 홈, 검색

기기의 사용성은 인간의 실수를 넓게 포용할 수 커진다.

실수를 용납하지 않거나 되돌릴 수 없는 상황에서의 선택은 많은 에너지를 소모할 수 밖에 없는 작업이기 때문이다.
컴퓨터용 사인펜으로 답을 기록할 때는 겨우 4~5개 중에 하나를 선택하는 것임에도 항상 신경이 쓰인다.
컴퓨터 자판에는 Backspace 키가 널찍하게 자리잡고 있고, 컴퓨터에도 휴지통이 있는 것도 실수를 만회할 수 있는 기회를 주기 위함일 것이다.
무엇인가 그 이전 상태로 돌이킬 수 있다는 것은 그래서 마음의 위안이 된다.

상태를 이전으로 돌이키는 것보다 더 강력한 방식은 '처음부터 다시' 이다. 뭔가 꼬이고 꼬여서 더 이상 해법이 없을 때, 처음부터 다시할 수 있다면 이 또한 상당히 위안이 된다. 컴퓨터도 뭔가 잘 안된다 싶을 때는 껏다 켜거나, 혹은 format이라는 극약 처방이 있기 때문에 마음의 위안이 된다. 최악의 상황에서 한번에 상황을 역전시킬 수 있는 탈출구이기 때문이다. 사람에게는 최소한의 탈출구가 있어야 한다.

선택의 기로에서 하나를 선택하거나 혹은 잘 알지 못하는 상황에 접했을 때 가장 좋은 방법은 누군가에게 물어보는 것이리라. 검색이라는 것은 사람들이 가장 쉽게 문제를 해결하는 해법 중에 하나이다. 내가 아닌 다른 사람의 방법 혹은 내가 원하는 무엇인가를 빠르게 찾아내는 방법이 검색이 주는 이득이다.

이전, 홈, 검색
그렇기에 이 3가지는 기능성에 더하여 실수를 허용하는 인간에 대한 배려이다.


Windows Store App의 WebView에서 alert 가로채기

이미 Server Side에 구축되어 있는 Web Page를 Store App에서 재활용 하기 위해서 가장 손쉽게 사용할 수 있는 방법은 아마도 WebView를 활용하는 것이 아닐까 한다. 

물론 WebView control이 Internet Explorer와 많은 부분을 공유하긴 하지만 HTML5에 대한 처리 매커니즘이나 일부 script 기능이 원할히 동작하지 않기 때문에(혹은 의도적으로 제약하였기 때문에) Web Page를 WebView control에 맞추어 수정할 수 없는 상황에서는 어려움에 봉착하게 된다.

가장 흔히 접하는 문제는 web page 내에서 alert와 같은 함수를 사용하는 경우인데, WebView Contol의 경우 의도적으로 alert를 사용하지 못하도록 제한하고 있다. 

Web Page를 수정할 수 있는 경우라면 Store App 전용의 Web Page를 구성하거나, 혹은 Web Page에 접속하는 클라이언트의 정보를 근간으로 Store App에 적합하게 수정된 페이지를 내려 줄 수 있겠으나, Web Page를 수정할 수 없는 경우라면 다음과 같이 alert  함수를 재정의하는 방법도 괜찮아 보인다.


구현 방식은 매우 간단하다.


1. WebView의 NavigationCompleted Event Handler를 다음과 같이 구성한다.


private async void webView_NavigationCompleted(WebView sender, WebViewNavigationCompletedEventArgs args)
{
    string result = await webView.InvokeScriptAsync("eval", new string[] { "window.alert = function (alertMessage) { window.external.notify(alertMessage) };" });
}


2. WebView의 ScriptNotify Event Handler를 다음과 같이 구성한다.


private async void webView_ScriptNotify(object sender, NotifyEventArgs e)
{
    Windows.UI.Popups.MessageDialog msgDialog = new Windows.UI.Popups.MessageDialog(e.Value);
    await msgDialog.ShowAsync();
}


간단히 설명을 더하면 Page Load가 완료되면,  eval function을 이용하여 window.alert를 window.external.notify() 함수를 호출하도록 재정의한다. 이 함수가 호출되면, WebView의 ScriptNotify event가 raise 되므로, 이 때 e.Value를 통해 전달된 메시지를 Windows.UI.Popup.MessageDialog를 이용하여 화면에 출력하는 것이다.


이러한 기법을 Script Injection이라고 하는데, 원칙적인 해결책은 아니지만, 다른 방법이 없을 경우 대안으로 고려해봄직 한것으로 생각된다.


(위 코드에서 async/await의 사용방법에는 논란이 있을 수 있다. 비동기 함수로 부터 반환값을 받을 필요가 없거나, 작업의 완료를 대기할 필요가 없는 경우라면 이 처럼 async/await를 이용하여 state machine을 내부적으로 구현하도록 허용하는 것은 그리 좋은 방법이 아니다. 하지만 설명의 초점을 흐리지 않기 위해서 이에 대한 대응 코드는 의도적으로 제외 하였다.)


Wintellect의 Package Explorer 복잡한컴퓨터이야기

Wintellect의 Jeffery Richter가 Store App 개발시에 사용할 수 있는 유용한 Tool을 공개하였습니다.

저도 한번 써보니 이것저것 재미나고 유용한 기능이 많이 있습니다.

Tool에 대한 자세한 내용은 다음 URL을 확인하시면 됩니다.

http://channel9.msdn.com/Shows/Defrag-Tools/Defrag-Tools-66-Windows-81-Jeffrey-Richter-Wintellect-Package-Explorer

파일을 Download 하려면 http://www.wintellect.com/Resource-WinRT-Via-CSharp 링크에서 Source Code 링크를 클릭하셔서 다른 Sample들과 같이 Download 하셔야 하는데요, 귀찮기도 하거니와 다른 Sample들은 필요하지 않으실 수도 있을 것 같아서 실행 파일만 따서 첨부합니다.

혹시 문제가 되면 바로 내릴 것이기 때문에, 미리 받아 두셔도 나쁘지 않을 듯 합니다.


(종료) Jeffery Richter의 CLR via C# 4판 번역서 베타 리더를 모집합니다 복잡한컴퓨터이야기

최근에 마이크로소프트 MVP이신 남정현님과 함께 Jeffery Richter의 "CLR via C#" 4판 번역을 완료하였습니다.

이번 "CLR via C#" 4판은 2006년 2판, 2010년 3판 이후에 2012년에 개정 출간된 책입니다.

앞서 2006년에 출간되었던 2판은 송기수님께서 번역/출간하신 바가 있습니다만 그간 꽤나 많은 부분들이 추가/수정되었기에 번역서를 다시 출간하게 되었습니다.(4판에는 Windows8의 WinRT와의 상호운용에 대한 부분까지도 포함되어 있습니다.)

개인적으로는 Jeffery Richter의 "Windows via C/C++" 의 번역서 출간이 native code 개발 전문가들을 위한 책이었다면, 이번 "CLR via C#" managed code 개발 전문가를 위한 책이기에 더욱 감회가 깊습니다. (물론 이미 잊혀진 effective C#도 있지만...)

게다가 이번에는 마이크로소프트 MVP이신 남정현님과 공동 번역을 진행할 수 있어서 영광이었습니다.

출간에 앞서 역자들의 미진한 능력을 보완하고자 10~15분정도의 베타리더를 모집하여 책의 완성도를 높이는 작업을 하고자 합니다.

참여해주신 베타리더분들께는 완성본이 나오면 한부씩 보내드릴 수 있도록 하겠습니다.

베터리더분들이 검토해주실 것은 책의 약 3~4장 정도의 분량을 살펴보시고 내용을 수정하시고 의견을 주시는 작업이 될 것입니다.

참석을 희망하시는 분은 himskim@msn.com 으로 "베타리더 참석"이라는 제목으로 메일을 보내주시거나 이 블로그에 댓글과 함께 email을 달아 주시거나 혹은 facebook/twitter를 통해서 댓글 혹은 Re를 달아 주셔도 되겠습니다.

많은 분들의 참석을 희망합니다.

감사합니다.

Jeffery Richter의 CLR via C# 4판 번역서 베타 리더를 모집을 종료합니다. 폭풍 신청에 감사 드립니다. 신청하신 모든 분께 기회를 드리기가 조금 어려울 것 같습니다. 몇몇분께서는 안타깝게 참석하시지 못할 수도 있는데, 가능한 관련 기술에 전문성을 가지고 계신분들에게 우선권을 드리고 싶었고, 빨리 신청하신 분에게도 기회를 드리고자 하였습니다. 혹시 신청하였음에도 베타리더가 되시지 못하더라도 너무 노여워 마시기 바랍니다. 그분들께는 송구하다는 말씀 전합니다. 다시한번 진심으로 감사드립니다.

 


글쓰는 법을 잊어버렸나? 살다보면

제 블로근데 글이 잘 써지는지 확인차 써봅니다.
거참~ 너무 오래 방치했더니 쉰네 작렬입니다.
다음 글을 올릴때 까지만 이 글을 대문에 걸어둘랍니다.

습관의 힘 책이야기

"습관의 힘"
2012년이 시작되고는 책 읽기가 후순위로 밀려 많은 책을 읽지 못하였다. 아이들 책을 사줄 요량으로 서점에 들렀다가 빈손으로 나오기가 머쩍어서 베스트셀러 전시 코너에서 별 생각도 기대도 없이 사온 책.


이 책이 전하고자 하는 개인적인 습관의 문제들. 그리고 습관의 과학적인 분석. 그리고 그것을 어떻게 하면 바꿀 수 있다는 등의 내용을 몇 개 되지 않은 사회적 현상과 예를 이리저리 오려 붙이고, 보는 관점을 달리하여 기술한 책. 그렇게 하지 않으면 이 분량의 책이 나오지 않기 때문.
책 분량의 1/5 정도가 reference이다.(뭐하러 이렇게 장황하게 reference를 넣었는지 이해할 수 없을 정도다.)

책의 거의 마지막 문장이 이 책 전체를 대변할 수 있는 글이다.

p377, "웰리엄 제임스는 습관에 대해서, 또 습관이 행복과 성공에 미치는 역할에 대해서 많은 글을 남겼다. 그는 그의 대표작 '심리학의 원리'에서 한장을 통째로 습관에 할애하기도 했다. 그는 습관이 작동하는 원리를 가장 적절하게 비유할 수 있는 것은 물이라고 했다.
'물은 자신의 힘으로 길을 만든다. 한번 만들어진 물길은 점점 넓어지고 깊어진다. 흐름을 멈춘 물이 다시 흐를 때에는 과거에 자신의 힘으로 만든 그 길을 따라 흐른다.'"

이 책에서 특이한 점은 습관을 개인의 습관을 넘어서서 사회적 공통체의 습관에 대해서도 이야기 하고자 함에 있다.

p302, "사회적 습관이 그처럼 막강한 영향력을 갖는 데는 대규모 혁명이든 교회 혁신 운동이든 대다수 운동의 근저에 항상 세 단계 과정이 있기 때문이다.
첫 단계에서 사회 운동은 가까운 지인들 간의 우애와 강력한 연대감으로 시작된다.
다음 단계에서 사회 운동은 이웃과 집단을 하나로 묶는 약한 연대감과 공동체의 습관 덕분에 커져 간다.
마지막 단계에서는 사회 운동의 지도자들이 참여자들에게 새로운 습관을 심어 준다. 변화된 정체성과 주인 의식을 잉태하는 새로운 습관의 영향으로 사회 운동은 지속된다."

이러한 분석은 개인적 본업(에반젤리즘)에 대하여 시사하는 바가 일부 있어서, 머리속에 담아 두려고 생각한다.

이 책을 통해서 자신이 가지고 있는 나쁜 습관을 바꾸려는 방법을 얻고자 한다면 p377 부터 시작하는 부록부분의 14페이지 정도의 내용만을 읽어보는 것으로 족하다.

그저 그런 책.


[C++11] nullptr에 대해서 복잡한컴퓨터이야기

시간이 되면 C++에 대해서 틈틈이 글을 써보려도 합니다.

오늘은 무지하게 간단한 nullptr의 이야기를 해볼까 합니다.

nullptr은 C++11에 추가된 새로운 keyword 이며, null pointer를 의미합니다. 이것이 중요한 이유는 기존에 써오시던 NULL이라는 것의 정의가 0L 이기 때문에 태생적으로 혼돈스러울 수 밖에 없었던 몇가지 issue를 해결할 수 있기 때문입니다.
사용 법이야 간단합니다.

const char *p = nullptr; // p 는 null pointer가 되는 것이지요.
if (p) ...     // expression 평가는 fail 이겠지요
int i = nullptr;   // 이 구문은 이제 안됩니다. nullptr은 더 이상 int로 변환되지 않습니다

기존에 0과 NULL에 대해서는 정상적으로 동작합니다.

int *p1 = nullptr;
int *p2 = 0;
int *p3 = NULL;

if (p1 == p2 && p1 == p3) {...}

NULL은 실제로 어떻게 정의되어 있을지 조금 궁금하시죠? stdio.h 에는 NULL을 아래와 같이 정의하고 있습니다.(VS2012에서 살펴보았습니다.)

/- Define NULL pointer value *-
#ifndef NULL
#ifdef __cplusplus
#define NULL    0
#else
#define NULL    ((void *)0)
#endif
#endif

즉 C++에서 NULL은 정확히 0과 동일합니다.
여기서 한가지 말씀드리자면 nullptr은 std::nullptr_t 타입입니다. 다른 널 포인터 타입 들은 static_cast를 사용하면 casting이 가능합니다.

int *p4 = static_cast<std::nullptr_t>(NULL);    // 기존에 사용하던 널 포인터 타입인 NULL은 이렇게 casting하실 수 있습니다.
int *p5 = static_cast<std::nullptr_t>(0);    // 기존에 사용하던 0 는 이렇게 casting 하실 수 있습니다.

0 이나 NULL이나 모두 int type 이니까 아래와 같이 하면 어떨까 궁금하실 수도 있을 것 같습니다.

int *p6 = static_cast<std::nullptr_t>(1);    // 하지만 이렇게는 안됩니다.

std::nulptr_t는 nullptr을 위해서만 존재하는 type이라고 볼 수 있겠지요.

약간 더 실질적인 예제를 한번 살펴보겠습니다.

void f(int *ptr);
void f(int val);

f(nullptr);    // f(int *ptr)이 호출됩니다.
f(0);    // f(int val)이 호출됩니다.
f(NULL);    // f(int val)이 호출됩니다.

f() 함수가 위의 예와 같이 overloading 되어 있을때, 0이나 NULL을 썼을 경우 포인터로 평가되지 못하는 문제를 해결하였지요.

아래와 같은 template 작성에도 좋은 예가 있을 수 있습니다.

template<typename F, typename P>
void logAndCall(F func, P param)
{
    func(param);
}

void f(int *p);

f(0);        // 괜찮아 보입니다. void f(int p)가 정의되어 있지 않으므로 f(int *p)가 정상 호출 되지요
f(nullptr); // 당연히 됩니다.

logAndCall(f, 0); // 이것도 에러가 됩니다. P의 type이 int로 평가되기 때문에 func(int)를 찾게되겠지요
logAndCall(f, NULL); // 이것도 에러입니다. 위와 같은 이유입니다.
logAndCall(f, nullptr); // 오호라~ 이건 정상적으로 P가 std::nullptr_t로 추론됩니다. f(std::nullptr_t)를 찾지요. 이건 기존 포인터와 호환되므로 정상적으로 func(int *p)를 호출합니다.

nullptr과 nullptr_t 을 추가함으로서 제대로 널 포인터의 의미를 부여할 수 있게 된것 같아요.
이제는 NULL이나 0 보다는 nullptr을 꼭! 쓰시는 것이 좋을 것 같습니다.


windows 8 app 개발하려면 어떤 언어와 Library를 사용해야 하나? 복잡한컴퓨터이야기

왠만히 개발에 관심있는 분이라면 windows 8의 metro style app 이야기를 한번 정도는 들어 보셨을 것 같습니다.
C/C++ 를 사용하거나 C#이나 VB와 같은 .NET Language 혹은 Javascript로 app을 개발할 수도 있습니다.

다양한 App을 개발하려면 기본적으로 Platform이 다양한 기능을 제공해 주어야 함은 물론이고, 그에 맞는 다양한 API를 사용할 수 있어야 할 겁니다. 게다가 각각의 언어들이 windows 8 app을 개발하기 위해서 새로 만들어진 언어나 library가 아니기 때문에 기존에 익숙한 library를 얼마나 많이 활용할 수 있는가는 개발자들의 학습 시간에 큰 영향을 주기 마련이지요.

windows 8 app을 개발하기 위해서 어떤 library를 사용할 수 있는지에 대해서 구체적으로 살펴보고자 합니다.

어떤 언어를 사용하던지간에 windows 8의 metro platform이 가지는 특성을 사용해야 하기 때문에 전용의 API가 제공되어야 합니다. 보통의 경우 개발 언어별로 API를 제공하는 것이 일반적이고, 그러지 않기 위해서 COM과 같은 Binary 규격으로 API를 제공하기도 합니다만 windows 8 metro platform용 API는 단일의 binary로 C/C++, C#/VB, Javas-ript 모두에서 사용할 수 있는 방식으로 만들어졌습니다. 정말 이정도면 삽질도 보통 삽질이 아니었을겁니다. 
이런 이질적인 3개의 언어군(native/managed/script)에서 사용할 수 있는 공통의 binary라니요??? 하지만 마이크로소프트는 Modem COM 이라는 새로운 규격 하에 3개의 언어에서 쓸 수 있도록 단일의 binary를 진짜로 만들었습니다. 그리고 각 언어의 특성과 binary 사이의 간극을 메우기 위해서 language 별 projection layer를 간단히 걸쳐 놓았습니다.
만들다 보니 아무래도 script language와 library 사이에 간극이 가장 컷던 모양입니다. 여러가지 이유로 그럴 수 밖에 없었는데 가장 큰 이유는 아무래도 공통의 binary(library)가 C/C++로 작성되었기 때문이라고 강하게 추측 해봅니다.

이 binary의 이름이 바로 "Windows Runtime" 입니다. 그래서 어떤 언어를 사용하던 Windows Runtime을 사용하여야만 windows 8 app을 개발할 수가 있습니다.

이게 언어별로 구분해서 살펴보겠습니다.

1. C/C++
먼저 C/C++입니다. C/C++은 visual c runtime을 포함하여 win32와 모든 com api가 사용가능 library군에 포함됩니다. 그런데 windows 8 app은 새로운 platform이기도 하거니와 상당히 제약이 많은 platform이기 때문에 모든 api를 다 사용할 수는 없습니다. 그래서 windows 8 app을 개발할 때 사용할 수 있는 api와 사용할 수 없는 app을 구분짓고 header 파일 내를 2개의 영역으로 구분지어 두었습니다.

#pragma region Application Family
이 영역에 선언되어 있는 API들은 windows 8 app과 dekstop app 모두에서 사용할 수 있습니다.
#pragma region Desktop Family
이 영역에 선언되어 있는 API들은 desktop app에서만 사용할 수 있습니다.

Visual Studio를 사용하면 Windows 8 app을 개발할 때에는 #pragma region Application Family 이하에 정의된 API 들만 사용가능하도록 해주고, desktop app을 개발할 때에는 둘 다를 보여주는 식으로 개발자를 도와줍니다.

C/C++에서만 사용할 수 있는 또 하나의 library가 있는데요, Platform이라는 namespace 안에 모조리 구현되어 있고, exception이나 type과 관련되어 있는 내용이 많이 포함되어 있습니다.
Platform namespace에 대해 궁금하신 분이라면 아래 링크를 살펴보시면 되겠습니다.

정리하면 사용할 수 있는 API 군은 크게 3가지로 요약될 수 있겠습니다.
Windows API: Windows Runtime
http://msdn.microsoft.com/en-us/library/windows/apps/br211377.aspx
Win32 and COM API 중 사용할 수 있도록 허용된 API들
http://msdn.microsoft.com/en-us/library/windows/apps/br205757.aspx
Platform namespace 내에 정의된 class와 method 들
http://msdn.microsoft.com/en-us/library/windows/apps/hh710417.aspx

그리고 약간 불편한 사실 두 가지
단일의 runtime을 구성하기 위해서는 언어별로 약간의 고통들을 감수 해야 했습니다. C/C++도 상당한 고통을 치러야 했는데요, 첫번째로 API 사용의 복잡성에 직면하게 되었습니다. 마이크로소프트는 이러한 복잡성을 해결하기 위한 방책으로 CX(Component Extension)이라는 확장 규격을 언어에 추가하였습니다. 따라서 windows 8 app을 C/C++로 개발하려면 가능한 CX 확장 규격을 사용하는 것이 정신 건강에 좋습니다. 이를 기존의 C++과 구분하기 위해서 C++/CX라고 합니다.

나머지 하나는 일반적인 C/C++ 개발 idiom이나 style이 아닌 windows runtime을 사용하기 위한 개발 style을 사용해야 한다는 것입니다. 이는 마치 C/C++을 사용하지만 표현의 방식이 다른 언어인냥 느껴지기도 합니다.
아주 간단한 예를 들어보면 Windows::ApplicationModel::Resources::Management  식의 namespace를 사용하는 등이죠.
이는 C/C++의 언어규격에는 정확히 맞을지 모르나 기존의 C/C++ 개발자들이 즐겨쓰던 방식은 아님에 분명합니다.

2. C#/VB
사실 C#/VB 언어를 사용하던 개발자라면 windows 8 app 개발시에 가장 빠르게 app을 개발할 수 있습니다. Windows Runtime를 사용해야 하는 것은 당연합니다. 여기에 더하여 .NET의 BCL(Base Class Library)중 windows 8 app 개발에 사용할 수 있는 Type들만을 모아서 ".NET for Metro style apps" 라는 library를 만들었습니다. 이름이 이렇다 보니 영문을 읽다 보면 이것이 Library의 이름인지 아니면 매트로 스타일 앱을 위한 .NET이라고 해석되어야 하는 것인지 혼돈 될 수 있는데, 절대로 혼돈하면 안됩니다. BCL 중 windows 8 apps을 개발할 때 사용할 수 있는 subset 만을 모아둔 API군의 이름이 ".NET APIs for Metro style apps"입니다.

Windows API: Windows Runtime
http://msdn.microsoft.com/en-us/library/windows/apps/br211377.aspx
.NET APIs for Metro style apps
http://msdn.microsoft.com/en-us/library/windows/apps/br230232.aspx

3. Javascript
Javascript는 앞서 2개의 언어와는 상당히 간극이 큰 언어임에 분명합니다. 그래서 Javascript를 이용해서 Windows Runtime을 완전히 사용하기에는 쉽지 않았습니다. 그래서 Windows Runtime과 더불어 "Windows Library for JavaScript"라는 녀석을 같이 써야 제대로 app을 개발할 수가 있습니다.
이런 이유로 C/C++이나 C#/VB로 개발하는 코드에 비해서 Javascript code가 상당히 이질적이거나 구조적으로 달라보이게 됩니다.
또한 많은 문서에서 API의 사용 예제를 3가지로 제공하는 경우 C/C++과 C#/VB 그리고 Javascript로 나누어 제공하고, 2가지로 예제를 제공하는 경우 C/C++/C#/VB 그리고 Javascript로 나누어 제공합니다.
대부분의 문서에서 "Windows Runtime and Windows Library for JavaScript" 하나로 묶어 설명하는데 이는 Javascript만으로 Windows Runtime을 사용하기에는 불가능하지는 않으나 너무나 복잡하기 때문입니다.
그외 HTML5와 CSS를 사용할 수 있겠습니다. 이또한 혼돈하지 말아야할 것은 HTML5와 CSS를 사용하고 있지만 정확히는 HTML5와 CSS 규격의 일부를 확장하여 사용하고 있다고 보는 편이 적절해 보입니다. 또한 광의의 의미에서 HTML5는 엄청나게 다양한 API 군을 포함하게 되는데, 아직 recommended가 확정되지 않은 내용이 많고 그 전체를 다 지원하지도 않습니다 지원되는 API 군과 확장 feature를 살펴보시려면 아래의 "HTML/CSS for Metro style apps" 링크를 살펴보시기 바랍니다.

Windows API: Windows Runtime
http://msdn.microsoft.com/en-us/library/windows/apps/br211377.aspx
HTML/CSS for Metro style apps
http://msdn.microsoft.com/en-us/library/windows/apps/br229576.aspx

이정도 알려줬으면 이제 앱들 팍!팍! 만드십시오.
불친절한 명신


1 2 3 4 5 6 7 8 9 10 다음


facebook 프로필 위젯

트위터 위젯