Study - Programming/C/C++2007. 8. 29. 01:35

출처 : http://www.winapi.co.kr/clec/cpp2/15-1-4.htm

volatile

volatile 키워드는 const와 함께 변수의 성질을 바꾸는 역할을 하는데 이 둘을 묶어 cv 지정자(Qualifier:제한자라고 번역하기도 한다)라고 한다. const에 비해 상대적으로 사용 빈도가 지극히 낮으며 이 키워드가 꼭 필요한 경우는 무척 드물다. 어떤 경우에 volatile이 필요한지 다음 코드를 보자.

 

int i;

double j;

 

for (i=0;i<100;i++) {

     j=sqrt(2.8)+log(3.5)+56;

     // do something

}

 

이 코드는 루프를 100번 실행하면서 어떤 작업을 하는데 루프 내부에서 j에 복잡한 연산 결과를 대입하고 있다. j값을 계산하는 식이 조금 복잡하지만 제어 변수 i값을 참조하지 않기 때문에 i 루프가 실행되는동안 j의 값은 상수나 마찬가지이며 절대로 변경되지 않는다. 루프 실행중에는 상수이므로 이 값을 매 루프마다 다시 계산하는 것은 시간 낭비이다. 그래서 제대로 된 컴파일러는 이 루프를 다음과 같이 수정하여 컴파일한다.

 

j=sqrt(2.8)+log(3.5)+56;

for (i=0;i<100;i++) {

     // do something

}

 

j의 값을 계산하는 식을 루프 이전으로 옮겨서 미리 계산해 놓고 루프 내부에서는 j값을 사용하기만 했다. 어차피 루프 내부에서 j값이 바뀌는 것이 아니므로 이렇게 코드를 수정해도 원래 코드와 완전히 동일한 동작을 할 것이다. 똑똑한 컴파일러는 프로그래머가 코드를 대충 짜 놓아도 속도를 높이기 위해 자동으로 최적화를 하는 기능을 가지고 있으며 이런 암묵적인 최적화 기능에 의해 프로그램의 성능이 향상된다.

그렇다면 위 두 코드가 정말로 완전히 동일할까 의심을 가져 보자. j는 분명히 루프 내부에서 상수이므로 미리 계산해 놓아도 아무 문제가 없음이 확실하다. 그러나 아주 특수한 경우 최적화된 코드가 원래 코드와 다른 동작을 할 경우가 있다. 어떤 경우인가 하면 프로그램이 아닌 외부에서 j의 값을 변경할 때이다.

도스 환경에서는 인터럽트라는 것이 있고 유닉스 환경에서는 데몬, 윈도우즈 환경에서는 서비스 등의 백그라운드 프로세스가 항상 실행된다. 이런 백그라운드 프로세스가 메모리의 어떤 상황이나 전역변수를 변경할 수 있으며 같은 프로세스 내에서도 스레드가 여러 개라면 다른 스레드가 j의 값을 언제든지 변경할 가능성이 있다. 또한 하드웨어에 의해 전역 환경이 바뀔 수도 있다.

예를 들어 위 코드를 실행하는 프로세스가 두 개의 스레드를 가지고 있고 다른 스레드에서 어떤 조건에 의해 전역변수 j값(또는 j에 영향을 미치는 다른 값)을 갑자기 바꿀 수도 있다고 하자. 이런 경우 루프 내부에서 매번 j값을 다시 계산하는 것과 루프에 들어가기 전에 미리 계산해 놓는 것이 다른 결과를 가져올 수 있다. i루프가 50회째 실행중에 다른 스레드가 j를 바꾸어 버릴 수도 있는 것이다.

이런 경우에 쓰는 것이 바로 volatile이다. 이 키워드를 변수 선언문 앞에 붙이면 컴파일러는 이 변수에 대해서는 어떠한 최적화 처리도 하지 않는다. 컴파일러가 보기에 코드가 비효율적이건 어쨌건 개발자가 작성한 코드 그대로 컴파일한다. 즉 volatile 키워드는 "잘난척 하지 말고 시키는 대로 해"라는 뜻이다. 어떤 변수를 다른 프로세스나 스레드가 바꿀 수도 있다는 것을 컴파일러는 알 수 없기 때문에 전역 환경을 참조하는 변수에 대해서는 개발자가 volatile 선언을 해야 한다. 위 코드에서 j 선언문 앞에 volatile만 붙이면 문제가 해결된다.

 

volatile double j;

 

이 키워드가 반드시 필요한 상황에 대한 예제를 만들어 보이는 것은 굉장히 어렵다. 왜냐하면 외부에서 값을 바꿀 가능성이 있는 변수에 대해서만 이 키워드가 필요한데 그런 예제는 보통 크기가 아니기 때문이다. 잘 사용되지 않는 키워드이므로 여기서는 개념만 익혀 두도록 하자.

Posted by 머리
Study - Programming/C/C++2007. 8. 29. 01:31

#include <stdio.h>

int main(void)
{
 int line;
 char star[50] ="";
 int i = 0;

 printf("Line : ");
 scanf("%d",&line);

 for(i = 0 ; i < line; i++)
 {
  star[i] = '*';
  printf("%s\n",star);
 }
 return 0;
}

Posted by 머리
Study - Programming/C#2007. 8. 29. 01:30

using System;
using System.Threading;

public class ThreadExam1
{
    public static void Print1()
    {
        Console.WriteLine("첫 번째 Thread **");
    }

    public void Print2()
    {
        Console.WriteLine("두 번째 Thread **");
    }

    public static void Main()
    {
        Thread thread = new Thread(new ThreadStart(Print1));
        thread.Start();
        thread = new Thread(new ThreadStart((new ThreadExam1()).Print2));
        thread.Start();

        Console.WriteLine("세 번째 Thread");
    }
}


솔직히 말해 모르겠다 이거 뭐하는건지.. 스레드의 정의 자체는 알겠는데 이게 어떤 의미인지를 잘 모르겠다;; 일단 델리게이트 부분부터 다시 봐서 이 코드가 어떻게 돌아가는지부터 다시 공부해 봐야지..

Posted by 머리
Study - Programming/C/C++2007. 8. 29. 01:23
LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
 HDC hdc;
 PAINTSTRUCT ps;
 int i;
 switch (iMessage)
 {
 case WM_CREATE:
  SetTimer(hWnd,1,50,NULL);
  return 0;
 case WM_TIMER:
  hdc = GetDC(hWnd);
  for(i = 0 ;i <1000; i++)
  {
   SetPixel(hdc,rand()%500,rand()%400,RGB(rand()%256,rand()%256,rand()%256));
  }
  return 0;
 case WM_LBUTTONDOWN:
  hdc = GetDC(hWnd);
  Ellipse(hdc,LOWORD(lParam)-10,HIWORD(lParam)-10,LOWORD(lParam)+10,HIWORD(lParam)+10);
  ReleaseDC(hWnd,hdc);
  return 0;
 case WM_PAINT:
  hdc=BeginPaint(hWnd,&ps);
  EndPaint(hWnd,&ps);
  return 0;
 case WM_DESTROY:
  PostQuitMessage(0);
  return 0;
 }
 return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}
Posted by 머리
Study - Programming/C/C++2007. 8. 29. 01:19

LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
 HDC hdc;
 PAINTSTRUCT ps;
 static BOOL isDown = FALSE;

 static int oldx;
 static int oldy;

 switch (iMessage)
 {
 case WM_LBUTTONDOWN:
  oldx = LOWORD(lParam);
  oldy = HIWORD(lParam);
  isDown = TRUE;
  return 0;
 case WM_LBUTTONUP:
  isDown = FALSE;
  return 0;
 case WM_MOUSEMOVE:
  if(isDown == TRUE)
  {
   hdc = GetDC(hWnd);
   MoveTo!Ex(hdc,oldx,oldy,NULL);
   oldx = LOWORD(lParam);
   oldy = HIWORD(lParam);
   LineTo(hdc,oldx,oldy);
   ReleaseDC(hWnd,hdc);
  }
  return 0;
 case WM_PAINT:
  hdc=BeginPaint(hWnd,&ps);
  EndPaint(hWnd,&ps);
  return 0;
 case WM_DESTROY:
  PostQuitMessage(0);
  return 0;
 }
 return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}


별것 없다. 마우스로 드로잉 하는 예제


우선 WM_LBUTTONDOWN 메세지가 호출되면 oldx,oldy에 좌표가 저장되고, WM_MOUSEMOVE메세지에서 마우스가 움직일때마다 좌표를 읽는다. 그래서 oldx,oldy에서 마우스 위치까지 선을 그려내면 된다.


Posted by 머리
Study - Programming/C/C++2007. 8. 29. 01:17

int pow(int num1, int num2)//대충 보고 알수 있음
{
     int i;
     int result = 1;

     for(i = 0 ; i < num2 ; i++)
     {
          result *= num1;
     }

     return result;
}

//원리 : 2 * 9 = 2 * (2 ^ 3 + 2 ^ 0) = 2 * (2^3) + 2*(2^0)
//곱할 수(9)를 2로 인수분해 함

int mul(int num1, int num2)
{
     int i = 0;//루프 변수
     int result = 0;//결과

     while(num2 != 0)
     {
           //2로 인수 분해 - (1)2의 몇승을 해야num2의 초과직전인지 체크
          while(pow(2,i) < num2)
               ++;

          result += (num1 << i);//그 수만큼 num1의 시프트값을 결과값에 더한다

          num2 -= (int)pow(2,i);//그리고 2의 i승을 num2에서 뺀다
          i = 0;//루프 초기화
     }//num2가 모두 분해되어 0이 될때까지 루프

     return result;//결과값 리턴
}

int div(int num1, int num2)
{
     int i = 0;//루프 변수
     int result = 0;//결과

     while(num2 != 0)
     {
     //2로 인수 분해 - (1)2의 몇승을 해야num2의 초과직전인지 체크
     while(pow(2,i) < num2)
          i++;

     result += (num1 >> i);//그 수만큼 num1의 시프트값을 결과값에 더한다

     num2 -= (int)pow(2,i);//그리고 2의 i승을 num2에서 뺀다
     i = 0;//루프 초기화
     }//num2가 모두 분해되어 0이 될때까지 루프

     return result;//결과값 리턴
}

Posted by 머리
Study - Programming/C/C++2007. 8. 29. 01:15

  우선 C에서 거짓은 0으로, 0이 아닌 값은 모두 참으로 인식한다. 0은 거짓이 확실하지만 참은 굳이 1이 아니어도 된다는 말. 1을 하는 이유는 그냥 보편적이기 때문이다. 단, 다른 언어에서는 종종 보이는 true와 false라는 것을 표현해주는 데이터형이 C에는 없다.


  bool형은 이런 것을 보완하기 위해 C++에서 새로 나온 것이다.


bool ex = true; //ex에는 true가 대입

ex = !ex ; //ex에는 false(!true)가 대입

ex = (ex == false); //ex에는 true가 대입


  물론 이런식으로도 가능하다.


bool ex = -123; // true 대입

bool ex = 0; //false 대입


  다시 한번 체크하자. 참은 굳이 1일 필요가 없다. -123처럼 음수라도 0만 아니면 참이 된다.

 

  하지만 bool을 출력한다고 하면 이야기는 달라진다. 다음 소스를 보자

bool ex = true;

cout << ex << ',';

ex = false;

cout << ex;

 

출력 : 1,0

  즉 출력을 하면 false는 0, true는 1로 출력이 된다. 하지만 좀더 명확하게 true 또는 false로 표현해줄 필요가 있다. 그럴떄는 이렇게 하면 된다.

 

cout << boolalpha;

cout << true << endl;

cout << false << endl;

 

cout << boolalpha로 해주면 true 또는 false로 출력을 해준다.

 

참고로 C99에서는 bool형을 지원한다.

Posted by 머리
Study - Programming/C/C++2007. 8. 29. 01:13

혹시 이런 생각 해본적 있는가? 보통 함수의 인자의 개수는 정해져 있는데, printf함수 같은 경우는 그 수가 제한이 없지 않은가?


예전에 이런 것과 관련해서 함수 하나를 구현할 일이 있었는데 미루다 미루다 이제야(한 일주일 된듯 -_-;;) 한번 찾아 보았다.


먼저 printf 함수 원형을 한번 보자

int printf(const char*,...);

이렇게 되어 있다. 사실.. 이거는 컴파일러가 'printf(' 여기까지만 치면 원형을 보여주는데 쓸데없이 stdio.h를 열어보는 뻘짓까지 했다 ㅋ


한번 분석해 보자.


  우선 printf의 리턴 데이터 형식은 int형이였다. 이 함수의 리턴값은 출련한 변수의 갯수이다. 예를 들어 ("%d,"%d",a,b)했으면 리턴 값은 2.


 그리고 첫 번째 인자는 우리가 "name %s\b"하는 이런 거고.. 중요한 것은 두 번째 인자 '...'이다. 인자를 생략한다는 표시인데, 이 표시를 통해서 함수 호출 시 인자를 얼마든지 넣을 수 있게 된다. 그것을 처리하는 것은 원형에서 해줄 몫이고.. 그리고 이것을 '가변 인수'라고 한다. 뭐 자세한 사용법은 알아서 공부해볼것, 이건 대충 사용법만 보고 거기에서 합계 구하는 예제 있길래 안보고 만들어 본 것. 이해 자체는 그리 어렵지 않은데.. 음 좀더 공부해 봐야지.



#include
#include

int GetSum(int Num,...)
{
 va_list ap;
 va_start(ap,Num);
 int arg;
 int i;
 int Sum = 0;

 for(i = 0 ; i < Num ; i++)
 {
  arg = va_arg(ap,int);
  Sum+= arg;
 }

 va_end(ap);
 return Sum;
}

void main()
{
 printf("%d\n",GetSum(10,1,2,3,4,5,6,7,8,9,10));
}



참, 참고로 C#에서는 가변 인수를 사용하는 방법이 따로 지원한다. 이것보다 더 쉽게.. (맞나?) 그때는 이게 말 뜻 자체도 이해가 안되다가 아! printf! 해서 이해만 하고 그래서 뭘 만들어볼까할때 아이디어가 생각이 안나 넘어갔는데.. 이렇게 다시 해볼 기회가 생겨서 다행이다.  뭐 이거 찾다가 VB에서도 가변인수 쓸수 있다는거 알았고, VB,C# 둘다 연습해 봐야겠다 함.. 그리고 C/C++에서도 계속 공부하고..

Posted by 머리
나의 이야기/Note2007. 8. 29. 01:06

테크트리?

  스타 테크트리 가지고 흉내내는 속어다. 뭐 간단하게 말하면 자기가 프로그래밍 공부를 어떻게 해왔냐는 말이다. 주로 언어 관련 순서를 나타내고, 가끔씩 자료구조, 알고리즘,이산수학 이런것도 넣기도 하더라. 음.. 나는 언어를 이런식으로 익혀 왔다. VB -> C -> C++ -> C#,JAVA 물론 사이사이에 API,MFC 이런것들도 중간 중간에 끼어 있다. 뭐 어느것 하나 제대로 알고 있는건 아니지만 나름 뭔가 하고 있다고는 생각하고 있다.


  초등학교 3학년 때, 컴퓨터 입문 책 부록에(그 당시에는 부록 CD를 주면서 온갖 유틸리티를 담아 주곤 했었다.) QBASIC이 들어 있었다. 그리고 부록 CD 설명에 '프로그래밍 도구인 QBASIC이다.' 이렇게 적혀 있었는데, 이것이 프로그래밍이라는 단어를 알게 된 계기였다. 즉, 무슨 프로그램 돌아가는게 신기해서 '아~ 나도 이런거 한번 만들어 보고 싶다' 이런 생각은 하지도 않았다는 것이다. 그래서 그떄 컴퓨터 가르쳐 주시는 선생님한테 물어보니 아직은 어려워서 못한다고 하시더라. 근데 이상하게 그때 그게 그렇게 하고 싶었나보다. 나름 파워포인트의 링크 기능갖고 내컴퓨터 불러오고 탐색기 불러오고 한글 불러오고 하는 기능으로 (지금 생각하면 참..) 꺠작대고 하는걸 보고 나에게 던져 주셨던게 Visual Basic 5. 그래서 그때 멋도 모르고 동네 서점가서 VB책 두꺼운거 하나 사와서 혼자 이것 저것 해보고 했었다. 그 책이 현재 내 보물 1호, Visual Basic Programming Bible Ver 5. 수도 없이 읽어서 지금은 완전 너덜너덜해 졌지만 그래도 반도 아직 모르는 책이다. 그 이후에 중학교전후에 C를 배운 적이 있었는데, 그 때는 정말 아무것도 모르고 배웠을 것이다. 단지 VB랑 비슷했던 기본 문법 사항들만 가지고 놀았고, 함수,포인터 이런거는 사용할줄도 몰랐을 것이다. 더군다나 그 VB의 RAD툴에 익숙했던 꼬마가 콘솔가지고 놀아 봐라. 얼마나 몰라도 몰랐겠는가.

  그 후 중학교때까지는 거의 VB만 가지고 놀았다. 그게 지금 생각하면 나에게 독과 약 둘다 되었던 것 같다. 득이 되었다면 윈도우 프로그래밍을 좀더 쉽게 접글할 수 있게 되었다는 것이고, 독이 되었다면 쉬운것만 찾아서 그리 실력이 크게 늘지 못했다는 것. 아마 당시에 C로 시작했으면 반대의 상황이 되었을지도 모르지만 그렇다고 VB먼저 시작한게 후회되지는 않는다. 오히려 더 마음에 든다.

  고등학교때는 컴퓨터를 거의 접었었고, 대학교 붙고 나서 미치도록 C 공부를 했었는데, 그떄 실력이 제일 많이(들인 시간에 비해서) 늘은 것 같다. 이미 기본적인 문법은 거의 알고 있었고, 경험도 거의 10년 가까이 얕게 했든 깊게 했든 나름 이것 저것 만들어 보느라 쌓여 있던 덕인지 머리쓰는 부분에서 막히는 일은 별로 없어 포인터 같은 난해한 개념 이해하는데 시간을 많이 들일 수 있었다. 이때쯤에야 겨우 프로그래밍에 대한 윤곽이 잡히기 시작했다. 솔직히 그 이전까지만 해도 나는 함수같은것은 뭔지도 몰랐다. 이미 VB에서 프로시저가지고 줄기차게 써먹어 놓고도 뭔지 몰랐다는 것. 그런 것들이 뭔가라는 것이 머리가 어느정도 크고 나니 잡혀 왔나 보다. 그 이후에 C++배울때는, 정말 단기간(거의 2달도 안대서) 대충 사용할수 있게 되었다. 뭐 나름 시간투자를 한 이유도 있었겠지만 C++하면서부터는 VB의 객체사용 경험이 있어서 그런지 이해가 빨리 된 듯 했다. 지금은 C#이랑 JAVA 간간히 어깨넘어 익혀 보면서 자료구조랑 알고리즘 파고 있다. 그런 쪽의 경험은 나한테도 절대적으로 부족하니까.

  지금 생각하면 지금 동기들이 밟고 있는 테크트리랑은 많이 다르다. 시작한 언어 자체도 다르니까.. 하지만 이렇게 생각한다. '무슨 언어를 배우든 나중에는 다 비슷비슷하게 보일것이고, 문법을 떼는게 문제가 아니라 머리쓰는법을 익히는게 문제다.' 개인적으로 문제해결기법시간에 김경석 교수님이 가르쳐 주시는 취지는 잘 알겠는데, 그게 성공적이지 못한게 참 아쉽다. 어떻게 돌아가는지만 생각할수 있으면 문법이야 금방 하니까 문제가 아닌데..뭐 근데 당연한 결과일 것이다. 머리쓰는건 눈에 안보이는 결과물이고, 문법은 당장 눈에 보이는 결과물이니까.

  흠... 대충 두서없는 말은 이쯤하고, 개인적으로 다시 공부하라 하면 이런식으로 공부해보고 싶다. C->자료구조,알고리즘 -> C++ -> VB -> API -> MFC -> 쭈욱.

Posted by 머리
나의 이야기/Note2007. 8. 29. 01:01

  부산대 공과대학 정보컴퓨터공학부, 현재 내 소속이다.


  여기서 뭐를 배우냐고? 나는 잘 모르겠는데 이 과를 의외로 모르는 사람이 많다더라. 예를 들면 우리과에서 워드프로세서 다루는 법을 배우는 줄 안다던지..


  솔직히 말해 이과를 원해서 들어왔으면서도 여기서 뭘하는지 나도 잘 모른다.  다만 지금 배운걸 이야기하자면 물리,수학, 문제 해결 기법 그리고 앞으로 2학기때 배울 C랑 전기회로 이정도? 영어랑 교양은 일단 빼놓고. 얼마 전에 민제 선배 스터디 하면서 들은 이야기로는, 우리과를 나오면, 컴퓨터와 관련된 곳이라면 어디든지 달려가서 작업할 수 있는 엔지니어가 된다고 한다. 단순히 우리과에서 프로그래머를 양성한다고 생각했던 나로서는 나름 큰 충격이였다. 물론, 공과대학이니 물리, 수학 같은 것을 프로그래밍 할때도 필요한 것이니 당연히 배운다고 생각했지만, 그것을 프로그래밍 작업의 일부라고 생각했던 것과는 다른 개념이였다. 엔지니어라.. 이 과에 들어와서 막연히 프로그래머가 되어야지 생각했던 나로서는 오히려 프로그래머가 아닌 다른것으로 빠질수 있겠구나하는 실망감보다는 좀더 넓은 곳이였구나하는 기대가 더 컸다.

 

  그럼 이전에 생각했던 프로그래머라는 것에 대해 이야기해 보자. 나도 당장 실무에 들어가 본 적이 없으니 어떨지는 모르겠지만, 대학 와서 내 나름대로 공부해 보면서 생각해본 것들을 정리해 보면, 일단 프로그래머를 지향해서 컴퓨터 관련 학과를 나왔다고 해서 어릴적부터 생각해온 멋진 프로그램을 설계하고 학교에서 배운 지식으로 멋진 기법으로 코딩하는 그런 '프로그래머'가 된다는 생각은 바뀌었다. 즉 컴퓨터 공학도라고 프로그래머가 된다는 이야기는 아니란 이야기다. 물론 그런 사람이 되도록 교육은 받겠지만, 실무에 들어서면 프로그래머와 코더의 차이는 분명히 들어난다고 한다. 정말로 머리를 써서 아이디어를 내고 그것을 기획하는 사람과 그것을 인계받아서 손으로 짜기만 하는 사람들은 따로 있다고.. 그것이 프로그래머와 코더의 차이라고.. 음.. 내가 말하는 이런 것들이 옳지 않을 가능성은 매우 높다. 다만, 내가 나름 공부하고 돌아다니면서 해본 생각을 정리해 본 것이 이렇다는 것이다. 하지만 이런것은 분명 존재할 것이다. 그것을 가르는 것은 능력..(좀 암울하게 이야기하자면 대한민국에서는 학벌)



   그러면서도 컴퓨터 공학도가 배워야 할것은 참 많다.. 뭐 공과대학적 지식은 물론이고, 어느 블로그 기사에서 본 이야기로는 프로그래머 내지는 코더도 12개 정도의 언어는 기본적으로 읽어서 무슨 말인지는 알아야 하고, 3~4개 정도의 언어는 완벽히 다룰 줄 알아야 한다고 한다. 물리, 수학의 비중이 적은 우리 과는 이런 쪽에서 알아야 할게 많다.. 이렇게 생각할 수도 있겠다. 내가 하고 있는 언어는 지금 뭐뭐가 있지.. VB, C, C++, C#, JAVA,흠.. 생각보다 많진 않네..

Posted by 머리