'Programing/C언어'에 해당되는 글 29건

  1. [코드] QoS테스트용 myping 프로그램 (7) 2007/06/08
  2. errno 사용법 (2) 2007/05/13
  3. 리눅스 시스템 콜 퀵 레퍼런스 (2) 2007/05/01
  4. 초보자들이 반드시 지켜야 할 C언어 코딩 기법 (5) 2006/08/03
  5. higasijoe의 C언어 강좌 모음 (3) 2006/08/01
  6. 박용운님의 제1장 C프로그램의 구조 (2) 2006/07/31
  7. 프로그래밍 도구 _위키 문서 (3) 2006/06/26
  8. 코딩 공부를 위한 문제들 (4) 2006/03/15
  9. [강의노트][컴퓨터공학] 비주얼 베이직 (4) 2005/12/30
  10. [필수자료] C/C++ 무료 컴파일러 (Dev-C++ 5.0 beta 9.2 v4.9.9.2) [시리님글] (2) 2005/09/07
  11. 김동수님의 C 강의 13강 (2) 2005/08/19
  12. 김동수님의 C 강의 12강의 (2) 2005/08/19
  13. 김동수님의 C 강의 11강의 (5) 2005/08/19
  14. 김동수님의 C 강의 10강 (8) 2005/08/19
  15. 김동수님의 C 강의 9강 (6) 2005/08/19
  16. 김동수님의 C 강의 8강 (2) 2005/08/19
  17. 김동수님의 C 강의 7강 (2) 2005/08/19
  18. 김동수님의 C 강의 제6강 (6) 2005/08/19
  19. 김동수님의 C 강의 제 5강 (7) 2005/08/19
  20. 김동수님의 C 강의 제 4강 (3) 2005/08/19
  21. 김동수님의 C 강의 제 3강 (3) 2005/08/19
  22. 권남수 님의 문자열 처리 함수 (6) 2005/08/19
  23. 권남수 님의 화일 입출력 (2) 2005/08/19
  24. 권남수 님의 구조체 (3) 2005/08/19
  25. 권남수 님의 포인터응용 2 ♧ | (3) 2005/08/19
  26. 권남수 님의 전 처리기 2005/08/19
  27. 권남수 님의 기억 클래스 (4) 2005/08/19
  28. 권남수 님의 C의 함수 (3) 2005/08/19
  29. 권남수 님의 C 기본 개념 (1) 2005/08/19
ToS필드에 값을 넣기 위해서 수정한 myping프로그램 입니다..

출처 : http://www.cs.utah.edu/~swalton/listings/sockets/programs/part4/chap18/myping.c

헤더파일이 없어서 안되는거 약간 수정하고, tos기능 약간 추가 하였습니다.

Ping으로 받은 메시지에 0x80이 ToS 필드에 찍힐것입니다.

관련 내용은 소스 코드 129줄과 143줄 입니다.

myping_TOS.c

TOS테스트를 위한 ping프로그램


20070608 by 임헌정
참고 : http://www.cs.utah.edu/~swalton/listings/sockets/programs/part4/chap18/myping.c
http://www.4ellene.net

2007/06/08 17:08 2007/06/08 17:08

errno 사용법

from Programing/C언어 2007/05/13 00:35

#include <errno.h> 포함.


printf("errno = %d\n", errno);


해당 errno 의 값 확인은


asm-generic/errno.h

asm-generic/errno-base.h


에서 확인할 수 있다.


#include<stdio.h>
#include<string.h>
#include<errno.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<sys/types.h>

 

int main()
{
        int             fd;
        int             temp_errno;
        extern int      errno;

        fd = open("/woojinnesdfasdttest",O_RDWR);
        perror("open");
        printf("fd : %d\nerrno : %d\n",fd,errno);

        return 0;
}

/usr/include/asm/errno.h



참고 :

http://blog.naver.com/endfirst/20018919109

http://blog.naver.com/lucisky/80024165984


2007/05/13 00:35 2007/05/13 00:35

리눅스 시스템 콜 퀵 레퍼런스

윤 상배

yundream@joinc.co.kr

고친 과정
고침 0.82004년 3월 19일 23시
최초 번역

1. 소개

시스템 콜이란 리눅스 커널에 의해 제공되는 서비스이다. 예를 들어 파일에 쓰는 서비스를 이용하길 원한다면 프로그래머는 리눅스에서 제공하는 해당 시스템콜을 이용해서 프로그램을 작성한다. C를 이용해서 프로그래밍을 할경우 대부분의 시스템콜은 libc를 통한 포장(wrapper)함수형태로 제공받을 수 있다.

시스템 콜 함수에 대한 정보는 매뉴얼 페이지(man page)의 섹션 2번을 통해서 얻어올 수 있다. 예를 들어 read()시스템콜에 대한 정보를 얻기를 원한다면 man 2 read 하면 된다. 시스템콜에 대한 소개를 원한다면 man 2 intro를 이용하기 바란다.

# man 2 intro

시스템 콜을 사용하기 위해서 libc를 통한 포장함수를 호출하는 외에도 syscall()함수를 이용해서 직접 실행시키는 방법도 있다. 각각의 시스템콜은 고유한 번호를 가지고 있는데, syscall에 이 시스템 콜의 번호를 입력하는 방식으로 호출한다. 내부적으로 syscall은 0x80 인터럽트를 이용해서 커널에 명령을 전달한다.

시스템 콜함수들은 syscall.h 와 unistd.h 에 정의되어 있으며, 시스템 콜 테이블은 "arch/i386/kernel/entry.S"리눅스 커널 소스파일에 정의되어 있다.


2. 시스템 콜 예제

#include <syscall.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>

int main()
{
long ID1, ID2;

// 시스템콜의 직접 사용
// 시스템콜 번호 : 20
ID1 = syscall(SYS_getpid);
printf("%ld\n", ID1);

// libc를 이용한 시스템 콜
// 시스템콜 번호 : 20
ID2 = getpid();
printf("%ld\n", ID2);

return (0);
}

3. 시스템 콜 레퍼런스

표 1. 시스템 콜 레퍼런스

번호함수 이름설명소스
1exit()현재 프로세스의 종료kernel/exit.c
2fork()자식 프로세스의 생성arch/i385/kernel/process.c
3read()파일 지정자로 부터 읽기fs/read_write.c
4write()파일 지정자로 쓰기fs/read_write.c
5open()파일이나 장치열기fs/open
6close()파일 지정자 닫기fs/open.c
7waitpid()프로세스의 종료를 기다린다kernel/exit.c
8creat()파일이나 장치의 생성fs/open.c
9link()파일을 위한 새로운 이름 만들기fs/namei.c
10unlink()파일 혹은 참조된 이름을 삭제한다fs/namei.c
11execv()프로그램의 실행arch/i386/kernel/process.c
12chdir()작업디렉토리의 변경fs/open.c
13time()초단위의 시간 얻기kernel/time.h
14mknod()일반 혹은 특수파일의 생성fs/namei.c
15chmod()파일의 권한 바구기fs/open.c
16chown()파일의 소유자 변경fs/open.c
18stat()파일의 상태 얻기fs/stat.c
19lseek()파일에서의 위치 변경fs/read_write.c
20getpid()프로세스의 ID를 얻어온다kernel/sched.c
21mount()파일 시스템의 마운트fs/super.c
22umount()파일 시스템 마운트 해제fs/super.c
23setuid()실제 유저 아이디 설정kernel/sys.c
24getuid()실제 유저 아이디 얻어오기kernel/sched.c
25stime()시스템의 시간과 날짜 설정kernel/time.c
26ptrace()부모프로세스가 자식프로세스의 실행을 제어하도록 허가arch/i386/kernel/ptrace.c
27alarm()실정시간후 alarm시그널이 전달되도록 한다.kernel/sched.c
28fstat()파일 상태 얻기fs/stat.c
29pause()시그널이 전달될때까지 대기한다.arch/i386/kernel/sys_i386.c
30utime()파일의 엑세스시간과 수정시간을 수정한다.fs/open.c
33access()파일의 권한을 검사한다.fs/open.c
34nice()프로세스의 우선순위를 번경한다.kernel/sched.c
36sync()슈퍼블럭을 업데이트 한다.fs/buffer.c
37kill()프로세스에 시그널을 전송한다.kernel/signal.h
38rename()파일의 이름과 위치를 변경한다.fs/namei.c
39mkdir()디렉토리를 생성한다.fs/namei.c
40rmdir()디렉토리를 제거한다.fs/namei.c
41dup()열린 파일 지정자를 복사한다.fs/fcntl.c
42pipe()내부통신을 위한 채널을 생성한다.arch/i386/kernel/sys_i386.c
43times()프로세스 시간을 얻는다.kernel/sys.c
45brk()프로세스의 데이터 세그먼트 크기를 변경한다.mm/mmap.c
46setgid()real 그룹 아이디를 설정한다.kernel/sys.c
47getgid()real 그룹 아이디를 얻어온다.kernel/sched.c
48sys_signal()ANSI C 시그널 제어kernel/signal.c
49geteuid()effective 유저 아이디 가져오기kernel/sched.c
50getegid()effective 그룹 아이디 가져오기kernel/sched.c
51acct()프로세스 측정을 켜거나 끈다.kernel/acct.c
52umount2()파일시스템 unmountfs/super.c
54ioctl()장치 제어fs/ioctl.c
55fcntl()파일 제어fs/fcntl.c
56mpx사용되지 않음 
57setpgid()프로세스의 그룹 아이디 설정kernel/sys.c
58ulimit()사용되지 않음 
59olduname구식의 uname 시스템콜arch/i386/kernel/sys_i386.c
60umaks()파일 마스크의 생성kernel/sys.c
61chroot()루트디렉토리의 변경fs/open.c
62ustat()파일시스템의 통계 얻기fs/super.c
63dup2()파일 지정자 복사fs/fcntl.c
64getppid()부모 프로세스의 PID 얻기kernel/sched.c
65getpgrp()프로세스의 그룹 아이디 얻기kernel/sys.c
66setsid()세션과 프로세스 그룹 아이디 설정kernel/sys.c
67sigaction()POSIX 시그널 제어 함수arch/i386/kernel/signal.c
68sigmask()ANSI C 시그널 제어kernel/signal.c
69ssetmask()ANSI C 시그널 제어kernel/signal.c
70setreuid()실제 혹은 유효사용자 아이디의 설정kernel/sys.c
71setregid()실제 혹은 유효그룹 아이디의 설정kernel/sys.c
72sigsuspend()시그널 마스크를 일시적으로 대체한후 시그널을 기다린다.arch/i386/kernel/signal.c
73sigpending()시그널을 블럭하고 검사를 수행한다.kernel/signal.c
74sethostname()호스트이름 설정kernel/sys.c
75setrlimit()자원의 제한값을 설정한다.kernel/sys.c
76getrlimit()자원의 제한값을 얻어온다.kernel/sys.c
77getrusage()자원의 제한값을 얻어온다.kernel/sys.c
78gettimeofday()날짜와 시간을 얻는다.kernel/time.c
79settimeofday()날짜와 시간을 설정한다.kernel/time.c
80getgroups()포함된 그룹아이디의 목록을 얻는다.kernel/sys.c
81setgroups()포함될 르룹아이디의 목록을 설정한다.kernel/sys.c
82old_select()오래된 버젼의 입출력다중화arch/i386/kernel/sys_i386.c
83symlink()파일에 대한 심볼릭링크 생성fs/namei.c
84lstat()파일의 상태 얻기fs/stat.c
85readlink()심볼릭 링크의 연결된 파일 이름을 읽는다.fs/stat.c
86uselib()공유라이브를 선택한다.fs/exec.c
87swapon()파일과 장치의 스와핑을 시작한다.mm/swapfile.c
88reboot()리붓 시키거나 Ctrl-Alt-Del을 활성화/비활성화 시킨다.kernel/sys.c
89old_readdir()오래된 버젼의 디렉토리 내용읽기fs/readdir.c
90old_mmap()오래된 버젼의 메모리 파일 대응arch/i386/kernel/sys/i386.c
91mnunmap()메모리 페이지 해제mm/mmap.c
92truncate()파일의 길이 결정fs/open.c
93ftruncate()파일의 길이 결정fs/open.c
94fchmod()파일의 권한 변경fs/open.c
95fchown()파일의 그룹및 소유자 변경fs/open.c
96getpriority()프로그램의 우선순위 얻어오기kernel/sys.c
97setpriority()프로그램의 우선순위 설정kernel/sys.c
98profile()execution time profile 
99statfs()파일시스템 정보 얻기fs/open.c
100fstatfs()파일시스템 정보 얻기fs/open.c
101ioperm()set port input/output permissionsarch/i386/kernel/ioport.c
102socketcall()소켓 시스템콜net/socket.c
103syslog()커널 메시지 버퍼의 내용을 읽거나 클리어한다.kerne/printk.c
104setitimer()내부 타이머 설정kernel/itimer.c
105getitimer()내부 타이머 값 가져오기kernel/itimer.c
106sys_newstat()파일의 상태 얻기fs/stat.c
107sys_newlstat()파일의 상태 얻기fs/stat.c
108sys_newfstat()파일의 상태 얻기fs/stat.c
109olduname()최근 커널의 정보얻기arch/i386/kernel/sys_i386.c
110iopl()I/O privilege 레벨 변경arch/i386/kernel/ioport.c
111vhangup()가상으로 현재 tty를 중지시킨다.fs/open.c
112idle()0번 프로세스를 idel상태로 한다.arch/i386/kernel/process.c
113vm86old()가상 8086모드로 들어가기arch/i386/kernel/vm86.c
114wait4()프로세스의 종료를 기다린다. BSD 스타일kernelk/exit.c
115swapoff()파일/장치의 스와핑 끝내기mm/swapfile.c
116sysinfo()시스템의 정보 얻어오기kernel/info.c
117ipc()System V IPC 시스템 콜arch/i386/kernelk/sys_i386.c
118fsync()파일의 내부상태와 디스크상의 상태를 동기화 한다.fs/buffer.c
119sigreturn()시그널 핸들러와 클린업 스택 프레임으로 부터 반환arch/i386/kernel/signal.c
120clone()자식 프로세스의 생성arch/i386/kernel/process.c
121setdomainname()도메인 이름 설정kernel/sys.c
122uname()최근 커널의 정보 얻어오기kernel/sys.c
123modify_ldt()ldt를 가져오거나 설정한다.arch/i386/kernel/ldt.c
124adjtmex()커널 클럭을 조율한다.kernel/time.c
125mprotect()메모리 영역에 대한 접근을 제어한다.mm/mprotect.c
126sigprocmask()POSIX 시그널 제어 관련 함수kernel/signal.c
127create_module()적재가능한 모듈엔트리 생성kernel/module.c
128init_module()적재가능한 모듈 엔트리 초기화kernelk/module.c
129delete_module()적재 모듈의 삭제kernel/module.c
130get_kernel_syms()retrieve exported kernel and module symbolskernel/module.c
131quotactl()디스크 쿼터 수정fs/dquot.c
132getpgid()프로세스 그룹아이디 가져오기kernel/sys.c
133fchdir()작업 디렉토리 변경fs/open.c
134bdflush()start, flush, buffer-dirty-flush 데몬을 조정한다fs/buffer.c
135sysfs()파일시스템 타입정보 가져오기fs/super.c
136personality()프로세스 실행 도메인 설정kernel/exec_domain.c
137afs_syscall()사용하지 않음 
138setfsuid()파일 시스템 검사를 위해 사용되는 사용자 실별자를 설정kernel/sys.c
139setfsgid()파일 시스템 검사를 위해 사용되는 그룹 식별자를 설정 
140sys_llseek()읽기/쓰기 파일의 위치 이동fs/read_write.c
141getdents()디렉토리 내용을 읽어들인다.fs/readdir.c
142select()입출력 다중화fs/select.c
143flock()열린파일에 대한 권고잠금 적용및 제거fs/locks.c
144msync()메모리 맵과 파일의 동기화mm/filemap.c
145readv()벡터를 읽는다fs/read_write.c
146writev()벡터를 쓴다fs/read_write.c
147sys_getsid()세션리더의 프로세스 아이디를 가져온다kernel/sys.c
148fdatasync()파일의 디스크에 있는 in-core 데이터를 동기화fs/buffer.c
149sysctl()시스템 파라메터를 읽고 쓴다 
150mlock()메모리의 페이지 잠금mm/mlock.c
151munlock()메모리의 페이지 잠금 풀기mm/mlock.c
152mlockall()호출한 프로세스의 페이징을 금지시킨다mm/mlock.c
153munlockall()호출한 프로세스에 대한 페이징을 다시 가능하도록 한다.mm/mlock.c
154sched_setparam()스케줄 파라메터 설정kernel/sched.c
155sched_getparam()스케쥴 파라메터 설정값 가져오기kernel/sched.c
156sched_setscheduler()스케쥴 알고리즘 파라메터 설정kernel/sched.c
157sched_getscheduler()스케쥴 알고리즘 파라메터 값 가져오기kernel/sched.c
158sched_yield() kernel/sched.c
159sched_get_priority_max()정적 선행 범위를 가진다kernel/sched.c
160sched_get_priority_mix() kernel/sched.c
161sched_rr_get_interval()프로세스의 SCHED_RR간격을 가져온다.kernel/sched.c
162nanosleep()지정한 시간에 실행을 잠시 멈춘다kernel/sched.c
163mremap()가상 메모리 주소를 재대응시킨다mm/mremap.c
164setresuid()set real, effective and saved user or group IDkernel/sys.c
165getresuid()get real, effective and saved user or group IDkernel/sys.c
166vm86()8086가상 모드로 진입arch/i386/kernel/vm86.c
167query_module()query the kernel for various bits pertaining to moduleskernel/module.c
168poll()파일 지정자로 부터 이벤트를 기다린다fs/select.c
169nfsservctl()커널 nfs 데몬을 위한 인터페이스fs/filesystems.c
170setresgid()set real, effective and saved user or group IDkernel/sys.c
171getresgid()get real, effective and saved user or group IDkernel/sys.c
172prctl()프로세스상에서의 실행kernel/sys.c
173rt_sigreturn arch/i386/kernel/signal.c
174rt_sigaction kernel/signal.c
175rt_sigprocmask kernel/signal.c
176rt_sigpending kernel/signal.c
177rt_sigtimedwait kernel/signal.c
178rt_sigqueueinfo kernel/signal.c
179rt_sigsuspend arch/i386/kernel/signal.c
180pread()파일 지정자로 부터 위치를 가져오거나 읽는다fs/read_write.c
181sys_pwrite()파일 지정자로 부터 위치를 가져오거나 쓴다fs/read_write.c
182chown()파일 소유자 변경fs/open.c
183getcwd()최근 작업 디렉토리 가져오기fs/dcache.c
184capget()프로세스 기능의 설정값 가져오기kernel/capability.c
185capset프로세스 기능 설정하기kernle/capability.c
186sigaltstack()시그널 스택 문맥을 가져오가나 설정arch/i386/kernel/signal.c
187sendfile()파일 지정자 사이의 데이터 교환mm/filemap.c
188getpmsg()사용하지 않음 
189putpmsg()사용하지 않음 
190vfork()자식 프로세스 생성과 부모 프로세스 블럭arch/i386/kernel/process.c

출처 : JoinC / http://www.joinc.co.kr
참고 자료 : LINUX System Call Quick Reference


2007/05/01 16:07 2007/05/01 16:07
먼저 이 글을 읽고 숙지하기에 앞서 이 글은
순전히 C언어 프로그래밍 초보자들을 위한 코딩 기법을 설명한 것임을
알려드립니다. 자신이 초보자가 아니면 그냥 넘어가시면 되겠습니다.
그러나 제가 만나 본 대부분의 프로그래머들(중수 이상 역시 포함)은
이런 규칙을 전혀 지키지 않고 코딩하더군요..
제가 쓴 글을 읽고 코딩한다면 누가 보더라도 정갈하고 깔끔한
코드가 될 것입니다. 나중에 스스로 짠 코드가 뭔 소린지 몰라
한참을 헤메지 않도록 열심히 노력합시다.
그럼 본론으로 들어갑니다..


1. 변수의 이름

보통의 경우 변수의 이름은 아무 뜻도 없거나 무진장 줄여 자신이 짠
코드도 나중에 보면 무슨 소린지 무슨 내용인지 전혀 알아 보지 못하는
경우가 있습니다. 이럴 때 변수의 이름만이라도 변수의 용도에 맞춰서
쓴다면 그 얼마나 좋겠습니까..

변수의 이름을 정할 때는 반드시 헝가리안 표기법을 사용합니다.

코드:
int nCounter=0;

이런식으로 변수의 이름 앞에 변수의 종류를 쓰는 것입니다.

보통 숫자는 number의 앞 글자인 n, boolean 변수는 b, 포인터 변수는 ptr,
문자형 변수는 c, 문자열 변수는 str 등 변수의 이름 앞에 특징을 기술하는 것입니다.

아래의 예를 보시기 바랍니다.
코드:
nSum=0;
nGrandTotal=0;
cAlphabet=NULL;
strSum[6]={0,};
ptrNextChain=NULL;

sum=0;
grandTotal=0;
alphabet=NULL;
sum[6]={0,};
nextChain=NULL;

위와 아래는 보기에도 차이가 납니다.
특히 alphabet 변수와 nextChain 변수는 아래의 예만 봤을 때 무슨
변수인지 전혀 알아 볼 수 없습니다. 그러나 위의 예를 보게 되면
최소한 알파벳 변수가 문자형 변수이고 넥스트체인 변수가 포인터라는
것은 변수의 이름을 통해 유추할 수 있습니다.

2. 변수의 초기화
변수의 초기화는 대단히 중요하면서도 간과하기 쉬운 예입니다.
변수는 로컬 변수, 글로벌 변수를 불문하고 무조건 변수 선언할 때
초기화
를 해줍니다. 보통의 C 컴파일러는 변수를 초기화하지 않고
그냥 사용하는 경우(즉, 초기화 없이 변수의 값을 읽는 경우) 워닝
메시지를 뿌리거나 메시지 없이 계속 컴파일합니다. 이것으로 생기는
side-effect(부작용)은 컴파일러도 책임지지 않습니다.
프로그램 코드가 길어지면 길어질수록 이런 변수 초기화를 하지 않아
생기는 문제는 더더욱 찾기 어려워집니다.

3. 변수의 용도 또는 사용 목적 기술
보통 위의 방법을 지켜 선언하더라도 변수를 선언할 때는 아래와 같이 하는
프로그래머들이 종종 있습니다.
코드:
int nCounter=0, nSum=0, nMaxBound=0;

나중에 코드를 읽는데 보기에 대단히 좋지 않은 방법입니다.
헝가리안 표기법으로 변수의 이름을 설정했지만 사실상 대략적인
의미만 파악할 수 있을 뿐 그 정확한 용도를 알아보기 힘듭니다.
따라서 아래와 같이 코딩합니다.
코드:
int nCounter=0; /* for문의 카운터로 사용하기 위해 선언 */
int nSum=0;     /* 성적의 합을 저장하기 위해 선언*/
int nMaxBound=0;   /* 그래프의 최대 한계값을 저장하기 위해 선언 */

자, 어떻습니까? 변수를 여러줄에 나눠서 선언한다고 해서 컴파일
시간이 비약적으로 늘어나는 것도 아니고 주석을 많이 단다고 해서
지저분한 프로그램 코드가 되는 것도 아닙니다. 위와 같이 코드를
짜놓으니 변수만 보고서도 무엇하는 프로그램인지 대충의 감을 잡게 됩니다.
프로그램 코드의 분석은 변수의 용도를 파악하기만 해도 절반은 된 것입니다.

잔소리. 저는 최대한 표준 C언어에 가깝게 코딩합니다. 보통의
컴파일러는 표준을 어기더라도 약간 느슨하게 허용하는 경우가 있으나
컴파일러간의 이식률을 높이기 위해 반드시 표준을 지켜서 코딩합시다.

4. 줄 맞추기
이건 잔소리 안할래야 안할 수 없습니다. 제가 대학시절 수업을
들을 당시 C언어를 강의한다는 강사라는 사람도 줄맞추기를
대충하더군요.. 줄맞추기는 칼 같이 해야합니다. 이건 권고사항이
아니라 반드시 지켜야할 강제사항입니다. 줄 맞추기 위해서
스페이스를 두 번 뚜드리던 탭을 한번 하던 그것은 여러분들의
자유지만 어떤 방법을 쓰더라도 줄 맞추기는 통일성 있게
칼 같이 해줘야 합니다. 어떨 때는 스페이스 2번으로 했다가
어떨 때는 탭으로 했다가 하는 짓은 줄 맞추기를 아니한만 못합니다.
코드를 분석해야하는 사람의 입장에서는 굉장히 괴로운 일입니다.
결국에는 눈물을 머금고 코드 줄 맞추기를 한 뒤에 그제서야
코드를 읽기 시작합니다. 무심코 빼먹은 줄 맞추기가 여러 사람 괴롭힙니다.

5. 중괄호 쓰기
코드를 아름답게 하는 방법중에는 중괄호를 많이 쓰는 방법도 있습니다.
중괄호를 많이 쓰면 그만큼 코드를 읽기 편해집니다. 영역이 명시적으로
표시되기 때문이지요.. 예를 볼까요?
코드:
while(i>0) if(i>0) printf("안녕?"); else i--;

while(nCounter>0)
{
  if(nCounter>0)
  {
    printf("안녕?");
  }
  else
  {
    nCounter--;
  }
}

극단적인 예이기는 하지만 저런 식으로 코딩하는 양반들도
종종 있습니다. 프로그래머라고 할 수도 없는 사람들이지만 말입니다.
아래의 예를 보면 어디서부터 어디까지 무슨 기능을 하는지 명시적으로
표현되어 있습니다. 단 한줄의 코드라도 for, do ~ while, switch ~ case, if ~ else 등
중괄호를 사용할 수 있으면 하라는 것입니다.
사실 중괄호는 아무데나 사용할 수 있습니다만 보통은 변수의 범위를
적절하게 설정하기 위해 코드 중간에 다음과 같이 사용하기도 합니다.
코드:
...
  {
    int nCounter=0;
    for(nCounter=10; nCounter > 0; nCounter--)
    {
      ...
    }
  }
...


6. Comment(주석)의 사용
누가 Comment를 주석이라고 이름 붙였는지 모르지만 주석이라는
단어의 사전적인 의미를 모르겠군요.. 그냥 주석은 이런저런 것이다는
것을 경험에 비추어 알고 있지만 말입니다. (일본식 단어인 것 같은
느낌을 팍팍 주는군요..) 저는 코멘트라고 하겠습니다.

용어야 어쨌거나 말았거나 코멘트는 많으면 많을 수록 좋다는 것이
제 지론입니다. 코멘트가 많으면 일단 프로그램을 읽는데 훨씬 수월해집니다.
긴 말 필요 없이 예를 보도록 하겠습니다. 아주 나쁜 예입니다.
코드:
int main(void)
{
  int n,m,i,j,x,y,z,dae,so;

  while(1)
  {
    printf("두수를 입력하시오 : ");
    scanf("%d,%d",&n,&m);

    if(n==0 || m==0)
    {
      break;
    }

    x=n;
    y=m;

    for(;;)
    {
      z=x%y;
      if(z==0)
      {
        break;
      }
      else
      {
        x=y,y=z;
      }
    }
    so=y;

    printf("%d\t,",so);

    dae=n*m/so;

    printf("%d\n",dae);
  }
  return 0;
}

아.. 줄 맞춤은 제대로 되었지만 언뜻 봐서는 이거 뭐하는 프로그램인지
도무지 알 수가 없습니다.. 5초 안에 알아보실 수 있겠습니까?
변수 이름도 엉망진창이고 주석도 하나 없고 도무지 알아 먹을 수 있는
코드가 아닙니다. 만약 이 코드를 5초안에 알아 볼 수 있다면
이 프로그램을 1시간 전에 짰거나 이 알고리즘을 자다 일어나서도 외울 수
있을 정도인 사람이거나 당신은 정말 코드 분석의 천재입니다.
훌륭한 예를 보겠습니다.
코드:
/*************************************************************
Promgrammed by Chronoshift at 2003.10.12
If you want to contact me, send email to taktaktak@aheheh.com
 
아규먼트
  없음

부작용
  없음

프로그램의 내용
  두 수를 입력 받고 입력 받은 두 수를 가지고
  먼저 최대공약수를 계산하고 최대공약수와
  입력받은 두 수를 가지고 최소공배수를 계산한다.
*************************************************************/

int main(void)
{
  int nInputNumber1  = 0;  /* 입력 받은 숫자를 저장하는 변수 */
  int nInputNumber2  = 0;  /* 입력 받은 숫자를 저장하는 변수 */
  int nNumberBuffer1 = 0;  /* 공약수 계산을 위한 임시 저장소 */
  int nNumberBuffer2 = 0;  /* 공약수 계산을 위한 임시 저장소 */
  int nBalance       = 0;  /* 나머지 값을 저장 */
  int nGCM           = 0;  /* 최대공약수 */
  int nLCM           = 0;  /* 최소공배수 */

  while(1)
  {
    /* 수를 입력 받는 부분 */
    printf("두 수를 입력하시오 <예) 43 22> : ");
    scanf("%d,%d",&nInputNumber1,&nInputNumber2);

    /* 입력이 잘 못 된 경우 */
    if(nInputNumber1==0 || nInputNumber2==0)
    {
      printf("This program not support 0 to input.\r\nPlease input other number again.");
      break;
    }

    /* 입력 받은 수를 최대공약수 계산을 위해 임시 저장 */
    nNumberBuffer1 = nInputNumber1;
    nNumberBuffer2 = nInputNumber2;

    /* 최대 공약수 계산 부분 */
    /* 최대 공약수를 구하는 알고리즘은(X/Y)%Z == 0 일때까지 무한 반복 */
    /* 만약 X=69 이고 Y=93이면 나머지 69가 된다 */
    /*  X  Y  Z       */
    /* 69 93 69       */
    /*   ↙ ↙        */
    /* 93 69 24       */
    /*   ↙ ↙        */
    /* 69 24 21       */
    /*   ↙ ↙        */
    /* 24 21 3        */
    /*   ↙ ↙        */
    /* 21 3 0         */
    /*   ↙           */
    /* 최대공약수 : 3 */

    for(;;)
    {
      /* 두 수를 나눈 나머지 계산*/
      nBalance = nNumberBuffer1 % nNumberBuffer2;
     
      /* 나머지가 0이면 GCM을 찾은 것이다 */
      if(nBalance == 0)
      {
        break;
      }
      /* 그렇지 않으면 알고리즘에 의해 Y를 X에 넣고 */
      /* 나머지를 Y에 넣고 재계산한다 */
      else
      {
        nNumberBuffer1 = nNumberBuffer2;
        nNumberBuffer2 = nBalance;
      }
    }
    nGCM = nNumberBuffer2;
   
    /* 최소공배수는 두 수를 곱하고 최대공약수로 나누면 된다 */
    nLCM = nInputNumber1 * nInputNumber2 / nGCM;

    printf("%d\t%d\r\n", nGCM, nLCM);
  }
  return 0;
}

얼마나 아름다운 코드입니까.. 코드를 모두 제거하고
주석만 남기더라도 뭐하는 프로그램인지, 어떻게 돌아가는지,
어떻게 코드를 짜야하는지 금방 알 수 있습니다.
이것이 바로 아름다운 1줄의 예술이라는 것입니다.
7. 맺음말..
더 이상 할 말이 없습니다. 앞에서 얘기한 6가지 원칙을 지키면
누구라도 한 줄의 예술을 할 수 있는 것입니다. 거만하게도 여러분들이
저를 보시기에 제가 고수라고 느끼실런지 몰라도 저 역시 하수일 뿐입니다.
진정한 고수라고 생각되는 사람이 저희 회사에 한 명이 있는데
그 양반 코드는 아주 소설입니다. 프로그래밍을 할 때 아주 소설책을 씁니다.
줄줄이 소설을 쓴 뒤에는 그 소설을 코멘트로 해서 코드를 써갑니다.
코드를 작성한다기 보다 쓴다고 해야 옳은 표현일겁니다.
물론 프로그래밍 마인드가 있어야 가능한 일이기는 합니다.
어쨌거나 코멘트를 바탕으로 코드를 작성해야 하는 원칙은 어느 언어든지
틀린 이야기가 아닙니다. 어렸을 때 전산학원을 다닌 사람들은 알 겁니다.
프로그램 언어를 배우기 전에 순서도를 배우죠. 그리고 순서도를 먼저
그리고 그것으로 프로그래밍하라고 배우죠. 사실은 순서도를 코멘트로
변환하고 그것으로 코딩해야 하지만 말입니다..
에이 모르겠다.. 역시 저는 글쟁이는 안되나 봅니다.
찝찝하더라도 여기서 끝입니다. -끝-

출처 : TFH-Chronoshift

2006/08/03 06:04 2006/08/03 06:04