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가지를 동시에 하기엔 벅차다.

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

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: