Posts Tagged ‘C/C++’

Connecting to Facebook with the C++ REST SDK

It’s very difficult to find C/C++ library to use for Windows, Mac ( and others ). There are some open sources, but they are kind of old and not updated. One of probably good thing is..  a module in MoSync library, but I worry about their license.

However, I found one on Microsoft Team blog about how to use “C++ REST SDK” for Facebook.

Connecting to Facebook with the C++ REST

The SDK is not made specifically for Facebook. It’s rather general.
So, people can access Facebook by doing things for themselves with the SDK.
( It’s like to use cURL for Twitter, although there is an existing library called twitcurl. )

Anyway, I wonder about login process with that. So, let’s read it.
The library itself can be obtained here.

Unexpected behavior of Win32 when checking serial ports.

I recently noticed very interesting behavior in ClearCommError() function of Win32.
This code returns how many bytes there are in incoming buffer for a serial port.

DWORD CSerialPort::BytesWaiting()
  //Validate our parameters

  //Check to see how many characters are unread
  COMSTAT stat;
  return stat.cbInQue;

void CSerialPort::GetStatus(COMSTAT& stat)
  //Validate our parameters

  DWORD dwErrors;
  if (!ClearCommError(m_hComm, &dwErrors, &stat))
    DWORD dwLastError = GetLastError();
    TRACE(_T("CSerialPort::GetStatus, Failed in call to ClearCommError, Error:%d\n"), dwLastError);

However, after actually debugging it I found out that there are cases where

  • The number of bytes in its incoming buffer doesn’t increase while it is calling BytesWaiting() to see if it received enough bytes to read. Then, it should read its incoming buffer for the given COM port to have BytesWaiting() starts to return accumulated number of bytes after reading.
  • When BytesWaiting() returns 0, you still need to read the buffer not to fail in detecting any further data arrived from the other side of communication. reading 0 bytes in this case, will cause the BytesWaiting() keeps returning the number of bytes read after that point.

Normally, whether you read or not, callying BytesWaiting() correctly reports the number of bytes in an incoming buffer.
However, if any of those listed above happens, it stops reporting correct number of bytes.

So, this code fails.

int CLensControllerDlg::ReadIncomingPacket(BYTE incomingBuffer[], int numOfBytesToRead, bool *pShouldGiveUp)
     DWORD bytesInReceptionQueue;
     int readNumOfBytes, extraReadNumOfBytes;

     readNumOfBytes = extraReadNumOfBytes = 0;

     // First read
     readNumOfBytes = m_pSerialPort->Read( incomingBuffer, numOfBytesToRead );
     int lengthToReadFurther;
     int secondTryReadLength = 0;

     static int trialCount = 0;

     // Check if it needs to read once more
     if( (incomingBuffer[ 0] == (BYTE) 0x50) &&
           (incomingBuffer[ 1] == (BYTE) 0xAF ))
           lengthToReadFurther = static_cast<int >(incomingBuffer[4]) + 1; // payload length + check sum
            // Read length + 1 more ( 1 is for checksum )

            //!!!!! [1] !!!!!
            // There are cases where bytesInReceptionQueue doesn't have accumulated number of
            // bytes in a reception bufffer.
            while( (bytesInReceptionQueue = m_pSerialPort->BytesWaiting()) < lengthToReadFurther )
                Sleep( 3 ); // 10 msec

                //!!!!! [2] !!!!!
                // So, if the bytesInReceptionQueue doesn't contain the accumulated number of bytes
                // through the iteration, try to read some.
                // Then it will start to work again.
                 if( trialCount > 10 )
                      if( bytesInReceptionQueue > 0 )
                            // Give another chance
                           secondTryReadLength = m_pSerialPort->Read( &incomingBuffer[readNumOfBytes], bytesInReceptionQueue );
                           readNumOfBytes += secondTryReadLength;

                           lengthToReadFurther -= secondTryReadLength;

                           trialCount = 0;

                            // let's see what it happens if try reading for 0 bytes and read further
                           BYTE temp[ 16];
                            int tempReadLength;

                            // bytesInReceptionQueue == 0
                           tempReadLength = m_pSerialPort->Read( &incomingBuffer[readNumOfBytes], bytesInReceptionQueue );
                           readNumOfBytes += tempReadLength;
                           lengthToReadFurther -= tempReadLength;

                            //// Once read, somehow, bytesInReceptionQueue starts to be accumulated again.
                            //bytesInReceptionQueue = m_pSerialPort->BytesWaiting();

                            //tempReadLength = m_pSerialPort->Read( &incomingBuffer[readNumOfBytes], bytesInReceptionQueue );
                            //readNumOfBytes += tempReadLength;
                            //lengthToReadFurther -= tempReadLength;

                           CString msgString;
                           msgString.Format( _T( ">> Will give up this incoming data : %x %x %x %x %x\r\n"),
                                                  incomingBuffer[0], incomingBuffer[1 ],
                                                  incomingBuffer[2], incomingBuffer[3 ],
                                                  incomingBuffer[4] );

                           WriteLogMessage( msgString );
                           TRACE( msgString );

                            if( pShouldGiveUp != NULL )
                                *pShouldGiveUp = true;

                           trialCount = 0;
                            return 0;

            // In the queue, now there are lengthToReadFurther or more to read.
           extraReadNumOfBytes = m_pSerialPort->Read( &incomingBuffer[readNumOfBytes], lengthToReadFurther );

     return (readNumOfBytes + extraReadNumOfBytes);

The code above was written while I was debugging. So, it’s not clean nor compact.
So, here is better version if you want to see.

int CLensControllerDlg::ReadIncomingPacket(BYTE incomingBuffer[], int numOfBytesToRead, bool *pShouldGiveUp)
     DWORD bytesInReceptionQueue;
     int readNumOfBytes, extraReadNumOfBytes;

     readNumOfBytes = extraReadNumOfBytes = 0;

     // First read
     readNumOfBytes = m_pSerialPort->Read( incomingBuffer, numOfBytesToRead );
     int lengthToReadFurther;
     int secondTryReadNumOfBytes = 0;

     // Check if it needs to read once more
     if( (incomingBuffer[0] == (BYTE)0x50) &&
          (incomingBuffer[1] == (BYTE)0xAF ))
          lengthToReadFurther = static_cast<int>(incomingBuffer[4]) + 1; // payload length + check sum
          // Read length + 1 more ( 1 is for checksum )
          while( lengthToReadFurther > 0 )
               Sleep( 1 ); // 10 msec

               bytesInReceptionQueue = m_pSerialPort->BytesWaiting();

               // If it's normal, just waiting until bytesInReceptionQueue >= lengthToReadFurther,
               // and read the whole "lengthToReadFurther" amount of data all at once.
               // However, sometimes the inbound buffer should be read to have further data accumulated.
               // If not,
               secondTryReadNumOfBytes = m_pSerialPort->Read( &incomingBuffer[readNumOfBytes], lengthToReadFurther );
               readNumOfBytes += secondTryReadNumOfBytes;

               lengthToReadFurther -= secondTryReadNumOfBytes;

     return readNumOfBytes;

CCheckListbox and item height

Well, MFC shows its age.

Although many fairly new programmers, who started to write code after the year 2000, think MFC is old, but in 90’s it was not.
It’s not as elegant as Cocoa or even new .NET ( with C#. .NET for C++ looks like too much overloaded truck with redundant stuffs on it. ).
However, it solves problems for its generation, and there was good reason for MS people to take such design.

However, they had to renovate it. There are many issues like control vs. view for similar components, inconsistent way to deal with widgets, etc.
Today I found a problem with item height for CCheckListBox. With VS resource editor, you can change “font size” of a dialog box or a window. What it actually does is not to change font size for widgets on them.

font size( I think it’s also a problem. What it actually does is to change “scale” of the coordinate system on that dialog box or window. Because the scale is changed, everything like button size is also changed as well as font size. So, it’s not right to name the property “Font(Size)”. )

Problem is that when an instance of CCheckListbox is instantiated and items are added to that, it checks whether each item height is bigger than its minimum size like this. ( Please focus on the last line. )

void CCheckListBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
  // You must override DrawItem and MeasureItem for LBS_OWNERDRAWVARIABLE

  CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);

  if (((LONG)(lpDrawItemStruct->itemID) >= 0) &&
    (lpDrawItemStruct->itemAction & (ODA_DRAWENTIRE | ODA_SELECT)))
    int cyItem = GetItemHeight(lpDrawItemStruct->itemID);
    BOOL fDisabled = !IsWindowEnabled() || !IsEnabled(lpDrawItemStruct->itemID);

    COLORREF newTextColor = fDisabled ?
      RGB(0x80, 0x80, 0x80) : GetSysColor(COLOR_WINDOWTEXT);  // light gray
    COLORREF oldTextColor = pDC->SetTextColor(newTextColor);

    COLORREF newBkColor = GetSysColor(COLOR_WINDOW);
    COLORREF oldBkColor = pDC->SetBkColor(newBkColor);

    if (newTextColor == newBkColor)
      newTextColor = RGB(0xC0, 0xC0, 0xC0);   // dark gray

    if (!fDisabled && ((lpDrawItemStruct->itemState & ODS_SELECTED) != 0))

    if (m_cyText == 0)
      VERIFY(cyItem >= CalcMinimumItemHeight());

It turned out that cyItem, which is height of an interested item at that moment, is less than the minimum height if the font size is set to 12.
So, MFC is not updated to work with its visual resource editor or vice versa.
At least there should be some property to choose item height based on chosen “Font size” on the visual editor. If the code for MFC presents relevant error message when debugging, it can be even better.

Anyway, if you set the item height using SetItemHeight() sufficiently, its debugger will not complain again. This is not documented in the section for CCheckListBox at all.

We complain that Apple let Mac OS X and its Cocoa framework behind due to its focus on iOS. ( kernel is the same on the both and Cocoa is almost same to CocoaTouch, but still.. ) However, Apple people keep updating their tool set to work properly with their framework. MS doesn’t seem to be considerate on this long-lived-but-dependable MFC framework. Yes, model-wise, .NET is better. But I often notice that .NET with C++ is too bloated and .NET with C# is too weak. For native environment, MS doesn’t have new framework to replace MFC for C++.
Nowadays, it doesn’t seem to me that there are many S/W engineers working with MFC/C++. So, probably they don’t ask much to MS. Well, in the world of Web app, Java and C#, where people usually justify “computers are getting faster. So, bytecode/VM language like C#/Java are OK.”. I think it’s understandable argument. But still it’s not sufficient to me. It’s like to use 486 computers with the speed of 386 computers. For convenience of using and learning a language, MS gave up many things in C#/.NET, which can be done more easily with C++/MFC/Win32.

LLVM’s Clang Compiler Is Now C++11 Feature Complete

OK. Now C++11 is said to be fully implemented in LLVM.
Although I kept opening my eyes on LLVM/C++0x/11 and have checked what were added, changed, etc, but it looks like that it’s time to swallow it instead of tasting.

How much complete a framework can be : MS vs. Apple

As a person who major in CS, I have interest in fundamental technology or techniques like compilers, OS, 3D graphics, computer vision, parallel systems & distributed systems. So, one of the reason I started to work with 3 major OSes, i.e. Windows, Unix and Mac, and have had lots of interest in their architectural design. Therefore I like to work with different frameworks and compare their design or philosophy behind them.

I think OS architecture is like a whole picture, while frameworks are each part of the OSes. What architectural design an OS has is reflected to its frameworks. When overall architecture design affect how they work, how their components are related one another and so on, frameworks for them should be designed as such. This is one of the reason I think Apple should have filed with OS architectures than their visual UI design against MS and Google.

Here, I would like to show the very difference between .NET and Cocoa. If you have followed ToolBox API and Win32/MFC, you will see similarity between Apple’s and MS’s. Also, there are similarity between Cocoa and .NET. I think it is because Objective-C/Cocoa is in the SmallTalk camp which test OOP concept in academia and geared toward SE, while C++ is in Simula camp which is more for real industry field. Because C++ is for more real field, it should have been compromised with many restriction like CPU speed etc. Also the C++ has been evolved for everything for all people. So, although C++ was introduced as THE OOP language, it has many different concept like meta programming, ad-hoc polymorphism. Also, because of that it also contains its syntax which became somewhat bad and some concept got to have many semantics. (e.g. extern vs. static ) C# is not too different from C++ in that. Although MS streamlined C# from C++. (actually C# was influenced more by Java at first. But as its name suggests it has the face of C++. # in its name is somewhat amusing. When they call it, don’t forget that it is called “sharp” rather than “pound”. # in musical notation is half higher than a note it is attached too. So, C# is C++ in that sense. ) I can feel those philosophy to be all for all from C#.
However, Objective-C and Cocoa was evolved to be focused to increase productivity. So, when using Objective-C and Cocoa, you naturally become to focus on core logic rather than “how to achieve that”. Objective-C is more simple and Cocoa is designed to be very intuitive and powerful.

OK. Let’s see how Objective-C/Cocoa achieves “GUI code on main thread”.

- (IBAction)doInThread:(id)sender
    [NSThread detachNewThreadSelector:@selector(doSomethingMethod:)
                             toTarget:self withObject:nil];

// Thread method
- (void)doSomethingMethod:(id)object
    // Calls appendLogMessage: on main thread
    [self performSelector:@selector(appendLogMessage:)
                 onThread:[NSThread mainThread]
               withObject:@"Do something..."

- (void)appendLogMessage:(NSString *)messageString
    NSTextStorage *textStorage = [m_logBoxView textStorage];
    NSUInteger theLastPos = [textStorage length];

    [m_logBoxView setSelectedRange:NSMakeRange( theLastPos, 0 )];

    [m_logBoxView insertText:[NSString stringWithFormat:@"%@\n",

It’s very intuitive. (Don’t confuse with that you don’t understand Obj-C code. Once you get used to it, it is very easy and straightforward. ) The appendLogMessage: is written just like a normal message/method.

Now, let’s check how it looks in C#/.NET.

#region MSDN way
private void m_doSomethingButton_Click(object sender,EventArgs e)
    m_choreThread = new Thread(new ThreadStart(this.StartThreadLoop));

    m_choreThread.Name = "MSDN Thread";

// Thread method
private void StartThreadLoop()
    // This is a thread loop
    int i = 0;

    while (i < 10)
        // 1. Call WriteLogMessage()
        this.WriteLogMessage(String.Format("Do chores hard!!! {0} from {1}", i, m_choreThread.Name));



// 2. Visit this in the non-main thread space
// 5. Visit this in the main thread space
private void WriteLogMessage(string msgString)
    // 3. If it is still in the context of a non-main thread
    if (m_logTextBox.InvokeRequired)
        WriteLogMessageCallback writeLogMessageDelegate = new WriteLogMessageCallback(WriteLogMessage);

        // 4. Invoke in its main thread space
        this.Invoke(writeLogMessageDelegate, new object[] { msgString });
        // 6. Call this in the main thread space.
        m_logTextBox.AppendText(msgString + Environment.NewLine);

I commented how things are visited in the C#/.NET case to help your understanding. So, to you, who use the framework, .NET case prevent you from concentrating on the main logic. In other words, you should know how things work in C#/.NET.

One of the virtue of OOP is data hiding and encapsulation. Although it says “Data Hiding”, it’s not only about “Data” but also “how it works internally.” C#/.NET fails in this area seriously as you can see. In other words, you should be aware of in which thread context the WriteLogMessage() is called and the method should be implemented with that knowledge.
Compared to that, messages in Objective-C/Cocoa can be written just like usual messages.

Then, are they really different? Couldn’t MS make their .NET framework as elegant as Cocoa? No. I don’t think so. It looks to me that Cocoa’s underlying code could be similar to that of .NET. The difference is that how much Apple people refined their framework by considering people who actually use their framework and design the framework to let people to focus on their own logic not on how Apple implemented this and that.

Then, let’s try to make it look similar to that of Objective-C/Cocoa.

#region Cocoa Way
private void m_doSomethinginCocoaWayButton_Click(object sender, EventArgs e)
    WriteLogMessage2(Environment.NewLine + "----------------------------" + Environment.NewLine);
    m_choreThread = new Thread(new ThreadStart(this.StartThreadLoop2));
    m_choreThread.Name = "Cocoa Thread";

private void StartThreadLoop2()
    // This is a thread loop
    int i = 0;

    WriteLogMessageCallback writeLogMessageDelegate = new WriteLogMessageCallback(WriteLogMessage2);

    while (i < 10)
                                 new object[] { String.Format("Do chores hard!!! {0} from {1}", i, m_choreThread.Name) } );



private void performOnMainThread( WriteLogMessageCallback methodToInvoke, object[] parameter )
    if (m_logTextBox.InvokeRequired)
        this.Invoke(methodToInvoke, parameter);

private void WriteLogMessage2(string msgString)
    m_logTextBox.AppendText(msgString + Environment.NewLine);


Don’t bother with the method name “performOnMainThread“. It’s not our interest. Whatever the name is, it doesn’t matter. What we need to focus on here is the pattern of how WriteLogMessage2() is called.
Also, additionally assume that Object class in .NET framework, which all classes are inherited from, contains the performOnMainThread(). Then like Cocoa, you can ask an object to invoke a given method on main thread. Then you, as a application program developer, can write the method to be invoked without worrying about knowing how those invoke system works.

Similar things happens with timer invocation. If you want to invoke a message at certain intervals in Cocoa, the code is very straightforward and very clean. However, in Win32/MFC case, the OnTimer() handler should check what timer triggers this timer event. In this case, it looks to me that Apple people utilizes signals and events. (Signal is so-called H/W events while event is called S/W event, if you want to be specific about the terms. ) I will not show sample code for that here.

Point here is that the level of refinement is higher on Apple’s. Cocoa framework is designed for SE more in mind, while MFC/.NET are more about “Let’s put this on the market as quickly as possible.” Good news is that.NET is more similar to Cocoa than their previous frameworks, because NeXT showed a future a while ago and MS looked to adopted that.

I always wonder why MS simply adopted Objective-C/Cocoa for their platform development. Well, C#.NET was a kind of a gun toward Java and MS languages can share the same .NET framework. So, there is slight difference, but even with Objective-C/Cocoa, there is a language bind. Well.. it’s true that people should make their own Cocoa equivalent.. yeah.. that can be the major issue to MS.
( Well.. I know that not choosing Obj-C/Cocoa or OpenStep by MS was also due to market situation, marketing, etc, but here I would like to focus on technical side. )

I wonder how F-Script people and Ruby Cocoa people bridged their language to Cocoa. (Script Bridging tech.. )

Unsung Hero, Brad Cox

개념적 용어를 keyword로 정의하게 되면, 설명할때 참 힘들어진다. 특히 “역사”를 모르는 사람들에겐. C#에는 reference type이란게 있는데, C#이 기본적으로 pointer가 없는 언어인만큼( VB사용자들을 끌어들여야 하니까. 그나저나 VB는 살아있나?), explicity하게도 혹은 class처럼 implicit한 것도 있다. 근데 설명할때 reference type이라고 말하면서 C++사용자에게 포인터를 쓰는 것과 같다고 말해버리면, “아. 포인터가 아니라 reference잖아요”라고 따지고 들 수있다. 아.. 그 reference가 아닌데. pointer(*)이던 reference(&)이던 다 레퍼런스인데…

C# 에는 reference type이란게 있는데, C#이 기본적으로 pointer가 없는 언어인만큼( VB사용자들을 끌어들여야 하니까. 그나저나 VB는 살아있나?), 명시적(explicit)으로 혹은 class처럼 묵시적인(implicit) 것도 있다. 근데 설명할때 reference type이라고 말하면서 C++사용자에게 포인터를 쓰는 것과 같다고 말해버리면, “아. 포인터가 아니라 reference잖아요”라고 따지고 들 수있다. 아.. 그 reference가 아닌데. pointer(*)이던 reference(&)이던 다 레퍼런스인데…

static allocation도 그렇고…

아.. 힘들다.
시 각적으로도 그렇다. C#에서 클래스가 레퍼런스 타입이면 그냥 Objective-C처럼 모든 객체는 포인터로 선언하면될 것이지, 생긴 것은 꼭 C++처럼 생겨서, 그냥 정적(static)정의 하듯이 하고선 그것이 reference type이라고 하면, C++에서 넘어온 사람들은 그런 변수를 함수 인자(패러미터)로 넘길때 고민하게 된다. “이거 내가 하는게 맞는거야?”

C#은 참 잘 만든 언어면서도 문제가 있는 언어다.
VB 사용자들을 끌어들이려면 확실하게 VB .NET을 밀던가, C/C++은 Apple이 Objective-C로 그러했듯이, 기존 컴파일러 많이 안바꾸고, 새 키워드도 많이 안넣으면서 하던가..
C++ .NET는 ISO에선가 C++로 부르지 말라고 까지 했잖은가?
포 지셔닝은 딱 Java인데, (Java도 C++과 비슷한 점이 많아서 장점이기도 하고 단점이기도 하고), C++의 신택스를 가지고 오고 이름도 C sharp 이니 ( C pound라고 하는 사람들은 없겠지? ) 자꾸 C++처럼 생각하게 된다는…

가만히 보면 Brad Cox가 Unsung Hero가 아닐까 한다.
C 를 만든 Dennis Ritchie나 C++의 Stroustrup, SmallTalk의 Alan Kay같은 명성을 누리지 못하지만, C 컴파일러를 거의 바꾸지도 않았으면서, 할 짓 다하는, 그것도 훨씬 간결하게.. 그런 언어를 만들어 냈으니, 이게 천재가 아니면 뭔가?

(같은 포스트 : )

S/W programming 쪽에서 한 단어가 여러가지 의미로 쓰이는 예

CS/E를 하다보면, 그리고 EE도 마찬가지지만 어떤 한 단어가 이 곳 저 곳에 쓰이는 경우가 있다.
아마 대표적인 것이 synchronous/asynchronous가 아닐까 한다.
전자 회로에서는 클럭에 맞추어서 동작이 될때, synchronous란 말을 쓰고, clock없이 될때 asynchronous란 말을 쓴다.
이 개념이 가장 그 단어들의 핵심적인 뜻이다. 근데 살짝 다른 곳에서는 다른 뜻이로 쓰이기 시작한다.
이를테면 data packet을 sender와 receiver가 ACK/NACK을 보내면서 서로 주고 받고 할때, synchronous란 말을 쓴다. 가만히 생각해 보면, 원래의 뜻과 일맥상통하는 부분이 있다. 그러므로 그것을 이해하면 “응.. 그래.. 여기선 그런 뜻으로 쓰였구나” 하고 알게 된다.

또 다른 것이 있다. 바로 이전 포스팅에 언급된 것인데, static이란 것이다.
C/C++을 할때, 이 static이란 녀석이 제일 변화 무쌍한 녀석이 아닐까 한다. 언제 이 놈이 쓰이는지를 정리해보자.

  1. static vs. extern
  2. static vs. dynamic
  3. static vs. volatile
  4. static vs. 일반 변수의 life time

우선 keyword로 존재하는 것은, 1, 3, 4번이다. 그리고 개념으로 존재하는 것은 2번이다.

자 살펴보자.

1. static vs. extern

static은 internal link를, extern은 external link를 의미한다.

즉 어떤 소스 파일에서 global하게 변수를 선언한다고 하자. 이때 extern과 static을 사용할 수있다.
default는 extern이어서 아무런 것도 사용하지 않고 선언을 하면, 기본인 extern이 사용된다. 이렇게 선언된 변수는 다른 소스 파일에서도 쓸 수가 있다. (extern 또한 복수개의 의미를 가진다.)
하지만 static으로 전역 변수를 선언하면, 그 파일 안에서만 그 변수를 보고 접근할 수가 있다. ( 이 사실은 4번과 관련이 있다.)

2. static vs. dynamic

여기서는 먼저 dynamic을 설명하는게 쉬울 것 같다.
dynamic하게 메모리를 할당한다, 객체를 생성한다라는 말을 많이 쓴다. 즉 C++ 같으면 new를, C 같으면 malloc류를, Objective-C 같으면 convenience method나 [[class alloc] init]를 이용해서 객체를 선언하는 게 그렇다. 개념이 쉬우리라고 본다.
자 여기에 반하는 언어가 뭘까? 동적의 반대말은 정적이다. 바로 static이 정적이다. 그래서 한국어로는 dynamic memory allocation을 동적 메모리 할당이라고 부르며, static memory allocation을 정적 메모리 할당이라고 부른다.

다시 한번 힘있게 말해보자.

“dynamic의 반대말은 static

동적의 반대말은 정적”

하지만 영어권에서 CS를 배운 사람들은 이런 용어, 특히  static memory allocation이란 말을 잘 모르는 것같다.

사실 dynamic memory allocation의 그런 memory allocation을 생각한다면 static memory allocaiton이란 것은 존재하지 않는다.

하지만 다음을 보자

int *p = new int[3];

int k;

첫 줄은 동적 메모리 할당이다. 그리고 그렇게 보이고, 그렇게 느껴진다.
그런데 둘째 줄도 메모리 할당인가? 컴파일러 관점에서 보면 메모리 할당이다. 그냥 개념적으로 보면 변수의 선언이지만. 왜 그런가? k라는 변수를 선언한 만큼, 4byte( 32비트 컴퓨터 이상) 혹은 2 byte ( 16비트 컴퓨터 – 8086/8088)의 메모리 공간을 확보해서 k라는 이름으로 assign해 놓는 것이기 때문에 그렇다.

이때 동적인 메모리는 heap에 생성되고, 정적인 메모리는 stack에 생성된다.
근데 stack은 어디에 존재할까? 바로 해당 함수 entry 부분에 생긴다. 함수가 시작하는 곳을 base로 잡고 (assembly language관점에서), 그 후에 function parameter들을 넣을 공간을 마련하고, 그 후에 stack공간이 생긴다. (반대던가?)
그리고 그 후에 실제 함수 이름과 함수 body가 시작된다.
C/C++과 같은 high-level language (요새 language라고 하면 JavaScript/HTML을 생각하는 세대에선 C/C++을 high level language라고 말하면 “틀렸다”고 하는 경우가 많다. 실제 이곳 저곳 미국에서 면접을  보다보니 그런 나이 어린 “면접관님”들의 주장에 밀려, 내 대답이 오답이 되곤 했고, 흡사 모르는 사람으로 취급당하기 일수였다. 짜식들.. 내가 영어를  native만큼 잘하면 아주 묵사발을 만들어 줄텐데. 근데 하나 영어를 못하니 장점이 생기는 것은, 잘 안따지게 되니, 잘 화를 안내게 되어 나의 혈압에도 좋고, 관계가 오래되면 미국 사람들 사이에 좋은 사람으로 인식이 된다는거. 한국에선 내가 좀 전투적이었는데… 지식의 옳고 그름에 대해선.. )의 입장에서 보자면 함수의 시작 주소(함수 이름이 시작되는.. 즉 body 직전)에서 값을 빼가면서 parameter니 stack 공간이니가 있는 것이다.

요새야 프로세서가 좋아져서 굳이 long jump니 near jump니 하는 게 없어졌지만, 예전엔 그게 참 critical했다. 그래서 stack에 생성할 수있는 크기에 제한이 있기도 했다. 즉 바꿔 말하면 local variable을 선언할 수있는 갯수 내지 크기 (결국은 크기다. 갯수는 갯수*변수의 크기=총 크기가 된다는 점에서, 한 요소가 되는 것이고 )의 제약이 생기는 것이다. 요새도 있던가? 요샌 long jump가 기본으로 되니까, 그리고 뭐 paged memory 이런거 잘 없으니까, 많이 제약이 완화가 된게 사실이다. 하지만 뭔가 아직도 잔재가 남아 있는 것 같긴하다. 아무튼.

근데 이 static을 C/C++에서는 keyword로 auto라는 놈을 쓴다. 하지만 그 놈은 default라 신경쓰지 않으면 “그런게 있었나” 싶다. 그런 존재감 없는 녀석들 중에  volatile이라던지 register도 있다. 그 네들에 대해선 다음에 쓰기로 하고…

이 wikipedia의 기사를 보면 auto variable은 local variable이라고도 하는데, 참.. 웃기는 말이다. 이래서 wikipedia 믿지 말라고 하는 것이고, 어떤 사람들은 wikipedia를 극도로 혐오하기도 한다. 잘못된 정보를 공신력을 가진 양 배포한다는 것이다. 근데 난 그래도 wikipedia가 좋다. 왜냐하면 모르는 것에 대해서, 좀 잘못되었더라도, 일단 어떤 거구나 하고 알 수있게 해주기 때문이다. 사족이지만 citizenium이나 Google의 knol이 좀 더 퍼졌으면 한다. knol은 포맷도 참신하고 좋은데, 그다지 활성화가 안되는 듯…

아무튼 왜 웃긴가? 함수 내에서 로컬 변수로 int *p = new int[3]이라고 선언하면, 그건 dynamic하게 할당한거잖는가? 근데도 p 자체는 로컬 변수잖는가?

아무튼 여기에서의 static이란 말은 C/C++에 있는 keyword로써의 static이 아니라, dynamic memory allocation의 그 dynamic에 개념적으로 반대가 되는 개념적인 말로써의 static이다.
힘든게.. 미국애들하고 말하다 보면, “아니야 auto라고 해. 너가 틀렸어”
그래 니들 무슨 말하는지 안다. 근데 니들 좀 우물 안에서 나올래? 누가 특정 언어에 국한된 용어를 말한데? compiler 공부하면 많이 쓰는 말이다. 라는 말을 해주고 싶어도. 순발력있게 말이 나오지 않아 못한다.

장점? “난 성격이 유하고 좋은 사람”이 된다. 단점? “나이만 들었고 뭣도 모르는 초짜가 졸지에 된다”

3. static vs. volatile

요거 요거. EE 출신들은 익히 기억하는.. 하지만 CS출신들은 그런게 있었나 싶은거다.
(여기에도 설명이 있다 한번 보자)

여기서도 역시 static은 개념적이지만,  글쎄다. 4번에서의 개념을 volatile에 대치되는 것으로 보면 keyword로 존재하기도 한다.
static vs. volatile이라고 할때는 사실 함수 내에서의 static이란 keyword를 써서 선언되는 variable과 살짝 다른 +알파의 뜻이 있다.

자 살펴보자.

우선 volatile. 언급했듯이 EE 출신들은 이 volatile을 익히 안다. 하지만 CS 출신들은 그다지. 왜 그럴까?

volatile은 “휘발성의”라는 뜻을 가진다. 즉 쉽게 날아간다. 즉 쉽게 변한다는 의미로 쓰인다. 그러면 도대체 “쉽게 변한다”는 무슨 의미로 쓴 말일까?

일반 변수는 procedural하게 보면, 현재 PC( program counter )가 한 라인 한 라인 지나가면서 수행을 할때, 그 코드에게 확실하게 제어를 당한다. 무슨 소리냐 하면, 코드에서 어떤 변수에 7라는 값을 넣으면 그 변수에는 7이란 값이 들어간다. 그리고 다른 라인에서 지우면 그 값은 지워진다.

반면에 volatile은? 내가 분명 사용하고 있는데 누군가 다른 넘이 그 값을 바꿀 수있으니, 그 현재 값을 믿지 마시오 하는 뜻으로 변수를 마킹해 놓을 때 쓴다. 요렇게 설명을 기억하고 있으면 당신은 아마 CS 출신일거다.
반면 EE쪽에선 어떻게 설명하냐하면 (하드웨어의 관점에선 변수는 어쨌거나 register에 매핑되니까. 물론 memory-to-register, memory-to-memory도 있지만, 현재의 제일 hot한 놈은 성능상 register에 매핑되는게 일반적이다.), 그 변수에 대응되는 레지스터를 어떤 시그널이 발생하던가, 뭔가가 아무튼 발생하면, 누가 그 레지스터를 건드리고 있던간에, 시스템에서 어떤 요인이 그 레지스터 값을 바꿔 놓을 수있다는 것으로 설명한다. 비슷하지? 두 설명이? 맞다. 사실 같은 말이다. 근데 좀 추상화를 했느냐, 손으로 만질 수있는 그런 물리적인 표현을 했느냐의 차이다.

근데 가만히 보자. 여기서의 static은.. 그럼 누군가 건드리지 않는다. 나만 건드린다라는 뜻도 된다. 즉 내가 건드리지 않으면, 그 값은 내가 마지막 건드린 그 상태로 있다. 즉 4번의 의미를 포함하는 면이 있다.

4. static vs. 일반 변수의 life cycle

“class variable, 함수내에 static으로 정의된 변수들”

딱 생각나는거 있지 않는가? 클래스가 인스턴스화 되기 전에도 존재하는 거.. 어떤 인스턴스에서도 같은 값으로 보이는 넘, 함수에 visit할 때에, 그전 invocation 값을 가지고 있는 넘.

아 그렇다. 인스턴스(객체/object) 혹은 함수/메소드와 같은 그 변수를 가지고 있는 넘들의 life cycle에 지배를 받지 않는 넘!

일반 변수는 함수내에 선언되었을 때, 그 함수에 visit를 하면, 초기화 된다. 그 함수 밖에서 그 넘을 볼 수가 없다. 혹은 그 클래스 밖에서 그 놈을 볼 수가 없다. (여기서 public 뭐 요딴거 이야기 하는게 아니라는 것은 아시리라고 본다. 그런 차원의 이야기가 아니다. 이런 것도 미국 애들하고 이야기할때 힘든 점. 말의 요지를 전혀 못 알아 먹는다는… )

하지만 static이라는 keyword를 가지고 선언된 변수는, 이런 그 포함하는 entity들의 life cycle을 넘어서 살아가게 된다.

자 근데, 이 마지막의 static이란 개념에, 첫번째의 의미로 쓰이는 그 static의 의미가 있을까?
가만히 생각해보자. 음.. 존재한다. 첫번째의 의미에서는 internal scope를 가지는 넘이었다. 그런데, 이것은 다른 측면에서 보면 이런 의미가 있다. 그 파일 안에선,  파일에서 벌어지는 무수한 함수의 호출, 객체의 생성/소멸.. 그런 것이 있음에도 불구하고, 그 파일 내에서는 전역적으로 살아있다. 그 scope와 값이. 이런 측면에서 보면, 첫번째의 static의 개념과 이 마지막의 개념 사이엔 일맥 상통하는게 있지 않은가?

지금까지 static에 대해서 알아보았다. 이런 설명은 나의 영어 실력으로는 미국애들에게 잘 할 수가 없다. 더군다나 미국 애들은 좀 생각을 단편적으로 해서.. 즉 한국 사람들은 한 일이 벌어지면 그 두단계 세단계 후를 생각하는 능력들이 있어서 척하면 아는데, 미국 애들/인도애들은 좀 단순해서 수를 한수 내지 잘해야 두수 정도밖에 못본다. 그래서 잠시 이야기 했지만 dynamic의 반대는 auto지 static이 아니야라고 따지고 드는 경우가 생기는 것이다. 누가 keyword 수준에서의 의미래? semantics의 의미지?

특히나 컴퓨터는 abstraction(추상화)을 많이 사용되는 것이다. 하드웨어에서는 무수한 circuit들이 칩으로 개념/관념화 된다. 한 칩안에 무수한 것들이 벌어지는데, 일단 만들어 놓고 나면, 이 칩은 이런 input이 들어가면 이런 output이 나와하고 추상화 해버린다.

이것이 compiler로 넘어오면서 또 한번 발생하고, low level language에서 high level language로 올라가면서 또 발생한다.

그래서 H/W 사람과 S/W 사람이 만나면 잘 싸우는 이유가 여기에 있는 것이다. 심하게는 삼성에 다닐때 어떤 과장님인가가 그랬는데, S/W하는 사람들 지네가 하는게 뭐냐는 것이다. H/W로 다 만들었는데, 그냥 그 input setting해주면 되는거 아니야? 그런다. 아. 안다. 지금 이 부분 읽으면서 실소를 한 그대. 근데 황당하게 들리겠지만, 내 귀로 똑똑히 들은 이야기다. S/W는 필요없다고까지 한다.
근데 이게 S/W를 하는 사람들 사이에서도 나타난다. OS를 만드는 사람이 보는 것과 생각하는 것은 compiler하는 사람이 하는 것과 다르다. 또 하위 언어를 하는 사람이 하는 생각은 상위 언어를 하는 사람이 하는 것과 다르다.
상위 언어래도 C/C++와 같은 언어를 하는 사람과 BASIC을 하는 사람이 다르며, 또 Java는 더더욱 다르다.

이젠 HTML/JavaScript도 언어라는 시대다. JavaScript는 script라고 부르지만, 그래.. 언어로 쳐 주자. 근데 HTML은? 여기서도 웃는 그대는 프로그래머. 안 웃고 왜  HTML이 언어가 아니냐고 따지신다면, 웹 디자인등을 하다가 코딩까지 하는 분들..
실제로 어떤 HTML 설명 책에 HTML을  “language”라고 써 놓은 것을 분명히 기억한다. 안타까운 것은 그게 어떤 책이었는지는… 그것을 읽는 순간.. 아.. 이 책은 내가 보면 안되는 책.. .그런 수준의 책.. 이라고 치부해 버려서.

이렇게 다른 추상화의 레이어에 서있는 사람들끼리 만나서 이야기하면, 특히나 어느 한쪽이 회사에서의 직책이 높을때, 그 반대의 사람은 완전히 바보가 되고, 뭣도 모르는 놈이 되버린다. 두 사람의 차이는 단지 어느 추상화의 레이어 위에 서있느냐일 뿐이다.

방금전에 objcguy님이 좋은 포스팅을 하나 하셨다. 어떤 레벨에서 보느냐에 따라 달라지는 가의  좋은 예이다.

부연 설명을 하자면, 이 포스트 바로 이전의 포스트에서 보여드린 예 중에 NSString 의 literal이 선언되는 위치에 대한 것이다. 일전에 stringWithString으로 만들어진 NSString 인스턴스의 retain count가 좀 이상하다는 포스팅을 한 적이 있는데, 거기에 nevyn이라는 사람이 왜 그런 행위가 도입되어있는지 잘 설명을 해주면서, 내가 단 커맨트에 그게 아니다라고 하면서 그 리터럴은 data section에 선언된다라고 했었다. 내가 assembly language로 프로그래밍을 했어도, 그 수준에서 계속 머리를 굴리는 것은 무척 피곤해서 (low level에서 생각하면 머리가 아프다. C/C++/Objective-C로 코딩을 할때도, 나는 부품화를 한다. 골치 아프고 여러번 이곳 저곳에서 불릴 놈들은 쉬운 이름으로 메소드나 클래스를 만들어 encapsulation을 시켜버리고, 그 다음부터는 그 안에서 지지고 볶고 하는거 기억할 필요없이, 아 저 클래스는, 저 함수는 이런거 하는 넘이라고 추사화 시켜버리고 그들을 써버린다. 프로그래머 중 안그런 분들이 어디 있을까마는, 나는 좀 그게 더 심한거 같다. 장점? 작업 초기엔 속도가 느리다. 하지만 그 후에 유지 보수때는 쉽고, modification을 국소적으로 할 수있고, 코드를 다른데서도 가져다 쓰기 좋다. ) 평소엔 그냥 C/C++/Objective-C 수준에서 한다.
그럴때  casual하게 쓰는 표현이 동적 메모리 할당은 heap에서, 정적 메모리 할당은 stack라는 표현이다. 미국에서 공부한 사람들은 이런 표현을 잘 안쓰는지도 모르겠지만 내 학번대에선 무척이나 많이 쓰인 말이다. 거의 정설이었다. 물론 여기에다가 컴파일러 제작자의 관점을 가져다대면, 이런 쉬운 표현은 무참히 부숴져 버린다. 위에 objcguy님이 언급하셨듯이 (이거 어떻게 기억하시지?), data section이라고 함수나 클래스나, 혹은 파일의 초장에 “앞으로 이런 이런 데이터를 쓸거니까 여기에 미리 정의해 둘께요” 하는 부분이 있다. 그게 쉽게 이야기하자면 data section이다. 리터럴은 여기에 정의가 된다. 즉 .DATA 혹은 DATA SEG… SEG END 인가 하는 x86 assembly language로 본 블럭에 존재한다. 그리고, 함수등을 정의하게 되면, 로컬 변수를 위한 스택영역이 할당되고 (앞에서 이야기했듯이 함수 body의 전에 있다. ) 그 스택 영역에 그 변수가 할당 된다.

void myFunction( ... )
   char *msg = "Test";

즉 위의 예를 보자면 “Test”는 data section에 들어가고, msg는 스택에 할당되며, 그 msg가 “Test”라는 data section으로의 jump offset을 가지게 된다. ( 8088때는 offset이었던 것으로 기억한다. 근데 글쎄? 지금 저 코드를 보면 msg가 “test”의 주소를 가져야 하기 때문에, offset만으론 안되겠지? 물론 data section까지의 거리야 얼마 안되기때문에 offset으로 해도 충분하겠다만, 요새는 assembly code/machine code들 보니까 그냥 다 full 주소를 가지고 점프해 버리더만. 오.. 좋은 세상이야. assembly code짜기 참 쉬운 세상이야. 예전에는 어셈 라인 세어서 near jump나 offset으로 커버 못하면 long jump로 하는데, 어쩌다 줄 수 잘못 세서, long jump해야 하는데 near jump 해 놓고는 뻑 나서, 왜 그러나하고 한참 시간 낭비하고 그랬는데…) 즉 assem레벨에서 보면, “Test”의 정의는 data section에 msg 변수만 stack에 있는 것이다.

근데…. 그냥 high level의 관점에서 추상화를 해 놓고 보자면, msg는 스택에 저장된 것이다. “Test”는 msg의 내용이다라고 단순화하게 되면.. 말은 “Test”라고 하면서도 중심은 msg에 있고, 어차피 msg는 “Test”를 가르키는 것이니, 그냥 스택에 저장된다라고 하는 것이다.
즉 여기서 “스택에 저장된다”고 하는 것은, “스택이냐 데이터 세그먼트냐”라는 더 구체적인 구별의 레벨이 아니라 다음의 예에서 보는 heap이냐 stack이냐 하는 관점의 표현이다.

void myFunc( void )
    int x = 2;
    int *p = new int[2];

좀 예가 무리가 있는 것은 사실인데, 2라는 값이 어디에 저장되어 있는가에 촛점을 맞추는게 아니라, x와 *p를 놓고 보면 x는 stack, p는 heap이라고 표현한다. 물론 이 예는 2라는 값 자체가 stack에 저장된다. 그래서 사실 저 위의 NSString literal예와는 다르다. 하지만 변수에 촛점을 맞추는 것이다.
이것을 stack variable, heap variable이라고 통상적으로 이야기했던 것으로 기억한다.

이렇게 기술쪽에는 같은 단어를 다르게 쓰는 경우가 왕왕있고 (symmetric이라는 말도 그렇지), 혹은 같은 기술쪽인데도 어느 레벨에서 보고 설명하느냐에 따라 서로 다른 레벨의 사람들이 볼때 “쟤 틀렸어”하는 경우가 있다.
추상화라는게 그렇지만, 단순화의 과정을 거치기 때문에, 어폐가 있지만, 대충 이렇게 이해하고 설명하는게 편하기 때문에, 그리고 이해가 쉽기 때문에 그렇게 한다라는 부분이 분명 존재한다.

예전에 어디서 면접을 볼때 일이다. Zoran이었던 것 같은데. (JPEG 칩으로 유명했던)
무슨 이야기를 하다가, 나에게 갑자기 re-entrant code를 어떻게 만드느냐를 물어봤다. 그 말을 하기전에 OS등에 대해서 casual하게 이야기를 하고 있었기 때문에, 내 머리는 당연히 OS 레벨에 있었다. compiler 레벨도 아니라.
그래서 잘 모르겠다고 했다. 나중에 면접 끝나고 생각해 봤더니.. 아뿔싸… 그 사람이 물은 것은 OS를 만드는 사람이 re-entrance를 구현하는 (그래서 컴파일러 등 그 위의 레벨 사람들이 이용할 수있도록 근간을 마련해주는) 그런 것이 아니라, 그냥 C/C++ 프로그래머가 어떤 함수에 semaphore를 설정해서 이미 한 쓰레드가 들어가서 있는데, 다시 들어가서 수행이 되어도 serial processing과 같은 결과를 보장하는 그런 re-entrant 코드를 어떻게 짜느냐는 질문이었다.
제길.. 영어로 small talk가 자유자재로 가능하면 예를 들어서 말하다가 머리속에서는 정리해서 답하면 되는데..
나에겐 영어가 또 하나의 processing time을 꽤나 차지하기 때문에, 기술적인 부분을 설명하면서, 질문자의 의도를 파악하고, 그것을 영어로 설명하면서, 이렇게 설명하면 맞나? 어떻게 설명하는 것이 좋을까란… 그러면서 기억을 더듬는 몇가지냐.. 5가지를 동시에 하기엔 벅차다.

영어 잘하시는 분들 부럽다…. 사실 이 말을 쓰고 싶어써!!!!!

%d bloggers like this: