brunch

매거진 Sinclair

You can make anything
by writing

C.S.Lewis

by Sinclair Feb 05. 2016

C의 자료형과 변수

너는 내 타입 III




타입 한정어들  


const: 값이 변경되지 못하게 만드는 타입 한정어입니다. const로 선언한 변수는 선언할 때 정한 값을 프로그램 실행 도중 변경할 수 없기 때문에 반드시 선언하면서 초기화를 함께 해야 합니다. 다만 const로 선언한 변수 일지라도 실제 상수는 아닙니다. 그러므로 상수를 사용해야 할 배열사이즈 선언에는 const 변수일지라도 사용해서는 안됩니다.  


int i ;

// 일반 정수형 데이터를 저장할 공간 i

int * i ;

// 일반 정수형 데이터의 위치(주소 값)를 저장할 공간 i

const int i ;

// 절대불변 정수형 데이터를 저장할 공간 i

const int * i ; i++; /* ++*i ; */

// 절대불변 정수형 데이터의 위치(주소 값)를 저장할 공간 i

// 주소는 얼마든지 바꿀 수 있다..

int * const i ; /* i++ ;*/ ++*i ;

// 일반 정수형 데이터의 절대불변 위치(주소 값)를 저장할 공간 i

// 값은 얼마든지 변경 가능하다.

const int * const i ; /* i++ ; ++*i ; */

// 절대불변 정수형 데이터의 절대불변 위치(주소 값)를 저장할 공간 i

// 주소도 값도 변경 불가능   


volatile: const가 프로그램 전체를 통해서 절대 변경할 수 없다는 타입 한정어인데 반해 volatile는 프로그램 실행 중 언제 어떤 외부 요소에 의해서 값이 변경될지 모르니 컴파일러는 volatile변수에 대해 어떠한 가정도 하면 안 된다는 것을 알리는 타입 한정어입니다. 일반적으로 선언한 변수를 초기화하지 않거나 사용하지 않으면 컴파일러는 오류를 발생할 때가 있습니다. 하지만 그 변수가 보통 하드웨어에 의해서 값이 변하거나 여러 프로세스가 동시에 한 영역을 공유해야 할 때 volatile변수를 사용하여 컴파일러에게 알리는 것입니다. 쉽게 말해 나 말고 다른 녀석이 건드릴 예정이다 라는 의미입니다. 일반적으로 주소 값을 갖지 않는 register변수는 volatile로 선언하지 않습니다.








이번 시간에는 들여쓰기와 주석을 적절히 사용할 것을 부탁 좀 드려야겠습니다.

아래 있는 프로그램은 1988년 The International Obfuscated C Code Competition (IOCCC)에서 obfuscated version of cdecl(인수의 스택 저장 순서는 오른쪽에서 왼쪽으로 하며 호출을 하는 쪽이 스택 공간을 삭제하는 호출방식) 부문 상을 받았다고 알려진 프로그램의 소스 입니다.


/* IOCCC, A 1988 winner was an obfuscated version of cdecl,

submitted by programmer Gopi Reddy */  

#include<stdio.h>

#include<ctype.h>

#define w printf

#define p while

#define t(s) (W=T(s))

char*X,*B,*L,I[99],M,W,V;D(){W==9?(w("`%.*s` is ",V,X),t(0)):W==40?(t(0),D(),

t(41)):W==42?(t(0),D(),w(" ptr to ")):0;p(W==40?(t(0),w("func returning "),

t(41)):W==91?(t(0)==32?(w("array [0..%d] of ",atoi(X)-1),t(0)):

w(" array of "),t(93)):0);}main(){p(w("input: "),B=gets(I))if(t(0)==9)L=X,

M=V,t(0),D(),w("%.*s.\n\n",M,L);}T(s){if(!s||s==W){p(*B==9||*B==32)B++;X=B;

V=0;if(W=isalpha(*B)?9:isdigit(*B)?32:*B++)if(W<33)p(isalnum(*B))B++,V++;}

return W;}  



제가 그나마 들여쓰기랑 줄 바꿈을 해봤더니 이 모양이 되었습니다.  


/* IOCCC, A 1988 winner was an obfuscated version of cdecl,

submitted by programmer Gopi Reddy */  

#include<stdio.h>

#include<ctype.h>

#define w printf

#define p while

#define t(s) (W=T(s))

char*X,*B,*L,I[99],M,W,V;

D(){

    W==9 ? (w("`%.*s` is ",V,X),t(0)) :

W ==40 ? (t(0),D(),t(41)):

W==42 ? (t(0),D(),w(" ptr to ")):

0 ;

p( W==40 ? (t(0),w("func returning "),t(41)) :

     W==91 ? ( t(0) == 32 ? (w("array [0..%d] of ",atoi(X)-1),t(0)):

w(" array of "),t(93)) :

     0

     ) ;

}  

main(){

    p(w("input: "),B=gets(I))

        if(t(0)==9)

            L=X,M=V,t(0),D(),w("%.*s.\n\n",M,L);

}  

T(s){

    if(!s||s==W){

        p(*B==9||*B==32)B++;

        X=B;

V=0;

     if( W=isalpha(*B) ? 9 :

         isdigit(*B) ? 32 :

         *B++)

            if(W<33) p(isalnum(*B))B++,V++;

    }

    return W;

}  



매크로를 풀었더니 이제야 printf()도 보이고 while도 보입니다. 한결 낫지 않습니까?  


/* IOCCC, A 1988 winner was an obfuscated version of cdecl,

submitted by programmer Gopi Reddy */  

#include<stdio.h>

#include<ctype.h>  

char*X,*B,*L,I[99],M,W,V;

D(){

W==9 ? (printf("`%.*s` is ",V,X),(W=T(0))) :

W ==40 ? ((W=T(0)),D(),(W=T(41))):

W==42 ? ((W=T(0)),D(),printf(" ptr to ")):

0 ;

while( W==40 ? ((W=T(0)),printf("func returning "),(W=T(41))) :

W==91 ? ( (W=T(0)) == 32 ?

(printf("array [0..%d] of ",atoi(X)-1),(W=T(0))):

printf(" array of "),(W=T(93))) :

0

) ;

}  

main(){

    while(printf("input: "),B=gets(I))

        if((W=T(0))==9)

            L=X,M=V,(W=T(0)),D(),printf("%.*s.\n\n",M,L);

}  

T(s){

    if(!s||s==W){

        while(*B==9||*B==32)B++;

        X=B;

    V=0;

    if( W=isalpha(*B) ? 9 :

isdigit(*B) ? 32 :

*B++)

            if(W<33) while(isalnum(*B))B++,V++;

    }

    return W;

}   







우리가 프로그래밍을 할 때 띄어쓰기나 줄 바꿈 또는 주석은 프로그램이 실행되는 데는 아무런 영향을 주지 않습니다. 하지만 프로그램은 hello world가 아닌 다음에야 혼자 작성하는 일이 아닙니다. 또 한번 작성해 놓았다고 해서 천년 만년 잘 돌아가지도 않습니다. 부모님이 우리를 낳으시고 애지중지 키우신 것처럼 계속 손을 봐야 합니다. 하지만 매일 매일 들여다 보는 경우가 아닌 다음에야 오랫동안 방치한 프로그램 소스를 어느 날 다시 접해보면 마치 남의 자식처럼 생소합니다. 아닌가요? 다시 한번 정중히 부탁 드립니다. 제발 소스를 작성하는 동안 주석도 적절히 달고, 띄어 쓰기와 줄 바꿈도 적절히 사용해 주길 바랍니다. 그냥 작성하는 것이 처음엔 빨리 진행 되는 것 같아 보여도 나중에 한 줄의 주석만 있었더라면 쉽게 이해 됐을 부분을 놓치고 엉뚱한 곳에서 삽질을 하고 있는 자신을 발견하게 됩니다. 큰 회사나 대부분의 제대로 된 프로젝트 매니저들이라면 반드시 프로젝트나 그 회사에서 사용하는 코딩 스타일을 먼저 정하고 개발을 시작합니다. 마음대로, 자신만의 색깔 대로 코딩 하는 것도 좋지만 정해진 룰을 따르는 것이 모두가 함께 행복해지는 길입니다. 주석은 스스로를 위해 작성하는 것 입니다. 다 하고 나중에 주석을 달겠다고요? 왜 인생을 그렇게 삽니까? 혹시 IOCCC대회 나갑니까? 출전해서 부디 일등 하길 바랍니다. 파이팅!





















무더웠던 지난 여름 낮잠을 자다가 시끄럽게 울어 젖히는 재앙 깉던 매미들을 죽일 듯이 바라보다가 문득 이런 생각이 들었습니다.


매미의 애벌레는 굼벵이 인데 매미는 보통 7년에서 10년을 땅 속에서 굼벵이로 지냅니다. 게 중에 오래 사는 놈은 17년을 산 놈도 있답니다. 그런 녀석들이 실제 매미로는 일주일에서 보름 정도, 정말 길어야  한달 밖에 못삽니다. 그러니 그 짧은 기간 동안 짝짓기를 못하면 자손도 없이 죽어야 합니다. 짝짓기 하려고 10년을 준비했는데 만약에 비라도 오면 녀석들이 하루 공칠 텐데 라고 생각해 보면 왜 매미들이 마치 죽어라 목숨 걸고 울어 젖히는지 이제 이해가 가시죠? 한 여름 열흘 정도 살기 위해 10년을 준비하는 녀석들을 생각하니 울음소리가 처량하게 까지 느껴지고 조금 참을 만 하더라구요.

그 와중에 나는 무엇인가를 이루기 위해 얼마나 참고 노력하는지 생각해보았습니다. 굼벵이 반의 반만큼도 못하는 제 자신이 부끄러웠습니다.


아무리 대기만성(大器晩成)이라지만 저는 제 그릇의 분량은 압니다. 하지만 그런 제가 감히 꿈을 꿉니다. 이 { Sinclair ˚C* } 를 읽는 여러분들 중에, 제 강의를 들었던 분들 중에 빌 게이츠를 능가하는 CEO가 나올 거라는 것을 말입니다. 부디 굼벵이처럼 오래 기다리며 부단히 노력하길 바랍니다.


흔히 사람들이 말하기를 물방울이 바위를 뚫는다고 합니다. 그런데 여기서 우리가 기억해야 할 것은 바위를 뚫은 것은 물방울의 힘이 아니라 바로 세월과 반복의 힘이라는 것입니다. 모르는 사아에 조금씩, 조금씩... 시나브로 참으로 무섭고도 힘이 되는 말입니다.




或生而知之 或學而知之

或困而知之 及其知之一也

생이지지 혹학이지지

곤이지지 급기지지일야


어떤 이는 나면서부터 알고

어떤 이는 배워서 알고

어떤 이는 힘들게 알게 되지만,

마침내 이루면 모두 같다.

- 中庸













#Sinclair #씽클레어 #싱클레어 #씽클레어도씨 #씨언어 #씨프로그래밍  #C언어 #Cprogramming #C_Programming #C #Programming #Clanguage #C_Language

매거진의 이전글 함수와 표준 I/O
작품 선택
키워드 선택 0 / 3 0
댓글여부
afliean
브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari