posted by bluelimn 2012.02.17 08:30

3. Memory mapped I/O
 

#include <sys/mman.h>

void * mmap(void* addr,//힌트일 뿐이며 보통 NULL을 넘긴다.

size_t len,

int prot,//접근권한

int flags,//추가적인 동작 방식

int fd,//대상

off_t offset);//시작위치

prot 옵션

PROT_NONE 권한없음

PROT_READ 읽기 가능한 페이지

PROT_WRITE 쓰기 가능한 페이지

PROT_EXEC 실행 가능한 페이지

flags 옵션

MAP_FIXED addr을 요구사항으로 취급하다록 지시. 해당주소에 mapping하지 못하면 호출실패

프로세스 주소공간에 대한 상세한 지식을 요구, 호환성이 떨어짐.

MAP_PRIVATE mapping을 공유하지 않음. 파일은 write후 복사로 mapping되며 변경된 메모리 속성은 실제 파일이나 다른 프로세스의 map에는 반영되지 않는다.

MAP_SHARED 동일파일을 mapping한 모든 프로세스들이 mapping을 공유.

read시 다른 프로세스가 write한 내용도 반영

mapping은 page단위로 구성됨 -> addr과 offset은 반드시 page size의 정수배가 되어야 함

ex)

void *p;

p = mmap (0, len, PROT_READ, MAP_SHARED, fd, 0);

if(p == MAP_FAILED) //ERROR

#include <unistd.h>

long sysconf(int name); // page size를 얻기위한 표준 method(POSIX)

int getpagesize(void); // page size를 얻기위한 표준 method(linux)

<asm/page.h>

PAGE_SIZE //정의된 정적 매크로, 실행시점이 아니라 컴파일 시점에서

시스템 페이지 크기를 조회

#include <sys/mman.h>

int munmap (void *addr, size_t len);

mmap()으로 만들어진 mapping 제거

ex)

#include <stdio.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcn시.h>

#include <unistd.h>

#include <sys/mman.h>

struct stat sb;

off_t len;

char *p;

int fd;

fd = open (filename, O_RDONLY);

if(fstat(fd, &sb) == -1) // ERROR

if(!S_ISREG (sb.st_mode)) //ERROR

p = mmap (0, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);

if(p == MAP_FAILED) //ERROR

if(close (fd) == -1)//ERROR

for(len = 0; len < sb.st_size; len++)

putchar(p[len]);

if(munmap(p, sb.st_size) == -1) //ERROR



장점

- 사용이 편리(다른 작업없이 메모리에 접근하기만 하면 된다. 포인터로 접근)

- 메모리 절약(추가적인 버퍼 메모리가 필요 없다.)

- 속도가 빠르다. (파일이 클수록, OS영역에 캐싱되어 있을수록 속도차이가 난다.)

- 다중 프로세스가 동일 객체를 메모리에 mapping할 때, 모든 프로세스가 자료를 공유한다

단점

- memory와 I/O가 주소공간을 공유(사용 가능한 주소 공간이 제한됨)

- page size의 정수배만 가능하다.(여분의 공간이 낭비됨)

- 연속적인 공간이 있어야 하므로 크기가 다른 mapping이 많으면 단편화 때문에 적당한 공간을 찾지 못할 수도 있다.(32bit일때. 64bit 주소공간에서는 크게 문제되지 않는다)

추가

- 파일이 모두 메모리에 올라오는 것이 아니라 메모리 access시 메모리를 할당해주고 I/O가 발생
 

mmap size 조정 // 리눅스 전용

#define _GNU_SOURCE

#include <unistd.h>

#include <sys/mman.h>

void * mremap (void *addr, size_t old_size,

size_t new_size, unsigned long flags);

접근 권한 변경

#include <sys/mman.h>

int mprotect (const void *addr, size_t len, int prot);

성공하면 0을 return.

mapping으로 파일 동기화 // fsync()와 유사

#incldue <sys/mman.h>

int msync (void *addr, size_t len, int flags);

flags 설정(OR연산 가능)

MS_ASYNC 동기화가 비동기식으로 일어나야 함

MS_INVALIDATE 캐시된 복사본이 유효하지 않음을 명세, 향후 이 파일의 map에 접근할 경우 새롭게 동기화된 디스크 내용을 반영

MS_SYNC 동기화가 동기식으로 일어나야 함,

msync() 호출은 모든 페이지를 드스크에 다시 쓰기 전까지 결과를 반환하지 않음.


madvise

memorymap에 포함된 page와 관련된 동작방식을 조언. 리눅스 커널은 기본적으로 동적으로 동작방식을 조율하며 성능을 최적화하지만 madvise는 부하상황에서 바람직한 캐시와 미리읽기 동작방식을 보장한다.

#include <sys/mman.h>

int madvise (void *addr, size_t len, int advice);

advice 설정(POSIX에서 정의한 의미)

MADV_NORMAL 특별한 조언을 하지 않는다.

MADV_RANDOM page에 random 순서로 접근하려고 함

MADV_SEQUENTIAL 낮은 주소에서 높은 주소의 순서대로 페이지 접근

MADV_WILLNEED 당분간은 지정된 영역에 있는 페이지에 접근하려고 함

MADV_DONTNEED 당분간은 지정된 영역에 있는 페이지에 접근하지 않음

advice 옵션(linux 2.6 kernel에서의 동작)

MADV_NORMAL 커널이 적절히 미리읽기 작업을 수행(평상시와 동일)

MADV_RANDOM 커널이 미리읽기를 비활성화함, 매번 물리적인 연산이 일어날 때마다 최소 자료만 읽음

MADV_SEQUENTIAL 커널이 공격적인(적극적인) 미리읽기 작업을 수행

MADV_WILLNEED 커널이 미리읽기 작업을 시작해서 페이지를 메모리로 읽어 들인다.

MADV_DONTNEED 커널이 페이지와 관련된 자원을 해제하고, 변경되었지만 아직 동기화되지 않은 페이지는 버린다. 이후 mapping된 자료에 대한 접근이 있으면 파일에서 페이지를 읽어들인다.

posted by bluelimn 2011.03.22 09:50

명  령  어

설                                               명

Data Transfer

MOV

Move

데이터 이동 (전송)

PUSH

Push

오퍼랜드의 내용을 스택에 쌓는다

POP

Pop

스택으로부터 값을 뽑아낸다.

XCHG

Exchange Register/memory with Register

첫 번째 오퍼랜드와 두 번째 오퍼랜드 교환

IN

Input from AL/AX to Fixed port

오퍼랜드로 지시된 포트로부터 AX에 데이터 입력

OUT

Output from AL/AX to Fixed port

오퍼랜드가 지시한 포트로 AX의 데이터 출력

XLAT

Translate byte to AL

BX:AL이 지시한 데이블의 내용을 AL로 로드

LEA

Load Effective Address to Register

메모리의 오프셋값을 레지스터로 로드

LDS

Load Pointer to DS

REG←(MEM), DS←(MEM+2)

LES

Load Pointer ti ES

REG←(MEM), ES←(MEM+2)

LAHF

Load AH with Flags

플래그의 내용을 AH의 특정 비트로 로드

SAHF

Store AH into Flags

AH의 특정 비트가 플래그 레지스터로 전송

PUSHF

Push Flags

플래그 레지스터의 내용을 스택에 쌓음

POPF

Pop Flags

스택으로부터 플래그 레지스터로 뽑음

Arithmetic

ADD

Add

캐리를 포함하지 않은 덧셈

SBB

Subtract with Borrow

캐리를 포함한 뺄셈

DEC

Decrement

오퍼랜드 내용을 1 감소

NEG

Change Sign

오퍼랜드의 2의 보수, 즉 부호 반전

CMP

Compare

두 개의 오퍼랜드를 비교한다

ADC

Add with Carry

캐리를 포함한 덧셈

INC

Increment

오퍼랜드 내용을 1 증가

AAA

ASCII adjust for Add

덧셈 결과 AL값을 UNPACK 10진수로 보정

DAA

Decimal adjust for Add

덧셈 결과의 AL값을 PACK 10진수로 보정

SUB

Subtract

캐리를 포함하지 않은 뺄셈

AAS

ASCII adjust for Subtract

뺄셈 결과 AL값을 UNPACK 10진수로 보정

DAS

Decimal adjust for Subtract

뺄셈 결과의 AL값을 PACK 10진수로 보정

MUL

Multiply (Unsigned)

AX와 오퍼랜드를 곱셈하여 결과를 AX 또는 DX:AX에 저장

IMUL

Integer Multiply (Signed)

부호화된 곱셈

AAM

ASCII adjust for Multiply

곱셈 결과 AX값을 UNPACK 10진수로 보정

DIV

Divide (Unsigned)

AX 또는 DX:AX 내용을 오퍼랜드로 나눔. 몫은 AL, AX 나머지는 AH, DX로 저장

IDIV

Integer Divide (Signed)

부호화된 나눗셈

AAD

ASCII adjust for Divide

나눗셈 결과 AX값을 UNPACK 10진수로 보정

CBW

Convert byte to word

AL의 바이트 데이터를 부호 비트를 포함하여 AX 워드로 확장

CWD

Convert word to double word

AX의 워드 데이터를 부호를 포함하여 DX:AX의 더블 워드로 변환

Logic

NOT

Invert

오퍼랜드의 1의 보수, 즉 비트 반전

SHL/SAL

Shift logical / arithmetic Left

왼쪽으로 오퍼랜드만큼 자리 이동 (최하위 비트는 0)

SHR

Shift logical Right

오른쪽으로 오퍼랜드만큼 자리 이동 (최상위 비트 0)

SAR

Shift arithmetic Right

오른쪽 자리이동, 최상위 비트는 유지

ROL

Rotate Left

왼쪽으로 오퍼랜드만큼 회전 이동

ROR

Rotate Right

오른쪽으로 오퍼랜드만큼 회전 이동

RCL

Rotate through Carry Left

캐리를 포함하여 왼쪽으로 오퍼랜드만큼 회전 이동

RCR

Rotate through Carry Right

캐리를 포함하여 오른쪽으로 오퍼랜드만큼 회전 이동

AND

And

논리 AND

TEST

And function to Flags, no result

첫 번째 오퍼랜드와 두 번째 오퍼랜드를 AND하여 그 결과로 플래그 세트

OR

Or

논리 OR

XOR

Exclusive Or

배타 논리 합 (OR)

String Manipulation

REP

Repeat

REP 뒤에 오는 스트링 명령을 CX가 0이 될 때까지 반복

MOVS

Move String

DS:SI가 지시한 메모리 데이터를 ES:DI가지시한 메모리로 전송

CMPS

Compare String

DS:SI와 ES:DI의 내용을 비교하고 결과에 따라 플래그 설정

SCAS

Scan String

AL 또는 AX와 ES:DI가 지시한 메모리 내용 비교하고 결과에 따라 플래그 설정

LODS

Load String

SI 내용을 AL 또는 AX로 로드

STOS

Store String

AL 또는 AX를 ES:DI가 지시하는 메모리에 저장

Control Transfer

CALL

Call

프로시저 호출

JMP

Unconditional Jump

무조건 분기

RET

Return from CALL

CALL로 스택에 PUSH된 주소로 복귀

JE/JZ

Jump on Equal / Zero

결과가 0이면 분기

JL/JNGE

Jump on Less / not Greater or Equal

결과가 작으면 분기 (부호화된 수)

JB/JNAE

Jump on Below / not Above or Equal

결과가 작으면 분기 (부호화 안 된 수)

JBE/JNA

Jump on Below or Equal / not Above

결과가 작거나 같으면 분기 (부호화 안 된 수)

JP/JPE

Jump on Parity / Parity Even

패리티 플레그가 1이면 분기

JO

Jump on Overflow

오버플로가 발생하면 분기

JS

Jump on Sign

부호 플레그가 1이면 분기

JNE/JNZ

Jump on not Equal / not Zero

결과가 0이 아니면 분기

JNL/JGE

Jump on not Less / Greater or Equal

결과가 크거나 같으면 분기 (부호화된 수)

JNLE/JG

Jump on not Less or Equal / Greater

결과가 크면 분기 (부호화된 수)

JNB/JAE

Jump on not Below / Above or Equal

결과가 크거나 같으면 분기 (부호화 안 된 수)

JNBE/JA

Jump on not Below or Equal / Above

결과가 크면 분기 (부호화 안 된 수)

JNP/JPO

Jump on not Parity / Parity odd

패리티 플레그가 0이면 분기

JNO

Jump on not Overflow

오버플로우가 아닌 경우 분기

JNS

Jump on not Sign

부호 플레그가 0이면 분기

LOOP

Loop CX times

CX를 1감소하면서 0이 될 때까지 지정된 라벨로 분기

LOOPZ/LOOPE

Loop while Zero / Equal

제로 플레그가 1이고 CX≠0이면 지정된 라벨로 분기

LOOPNZ/LOOPNE

Loop while not Zero / not Equal

제로 플레그가 0이고 CX≠0이면 지정된 라벨로 분기

JCXZ

Jump on CX Zero

CX가 0이면 분기

INT

Interrupt

인터럽트 실행

INTO

Interrupt on Overflow

오버플로우가 발생하면 인터럽트 실행

IRET

Interrupt Return

인터럽트 복귀 (리턴)

Processor Control

CLC

Clear Carry

캐리 플레그 클리어

CMC

Complement Carry

캐리 플레그를 반전

CLD

Clear Direction

디렉션 플레그를 클리어

CLI

Clear Interrupt

인터럽트 플레그를 클리어

HLT

Halt

정지

LOCK

Bus Lock prefix


STC

Set Carry

캐리 플레그 셋

NOP

No operation


STD

Set Direction

디렉션 플레그 셋

STI

Set Interrupt

인터럽트 인에이블 플레그 셋

WAIT

Wait

프로세서를 일지 정지 상태로 한다

ESC

Escape to External device

이스케이프 명령

MOVS 무브와 비슷한 작동을합니다


Push: sp 레지스터를 조작하는 명령어중의 하나이다.

스택에 데이터를 저장하는데 쓰인다.

ex:) Push eax

:스택에 Eax의 값을 스택에 저장한다.

ex:) Push 20

:즉석값인 20을 스택에 저장한다.

ex:) Push 401F47

:메모리 오프셋 401F47의 값을 스택에 저장한다.


Pop: 이또한 sp 레지스터를 조작하는 명령어중 하나

이다. 스택에서 데이터를 꺼내는데 쓰인다.

ex:) Pop eax

:스택에 가장 상위에 있는 값을 꺼내애서 eax에 저장

주의점: Push 의 역순으로 값은 스택에서 Pop 된다.


Mov: 메모리나 레지스터의 값을 옮길떄[로 만들떄]

쓰인다.

ex:) Mov eax,ebx

:ebx 레지스터의 값을 eax로 옮긴다[로 만든다].

ex:) Mov eax,20

:즉석값인 20을 eax레지스터 에 옮긴다[로 만든다].

ex:) Mov eax,dword ptr[401F47]

:메모리 오프셋 401F47 의 값을 eax에 옮긴다[로 만든다]


Lea: 오퍼렌드1의 값을 오퍼렌드2의 값으로 만들어준다.

ex:) Lea eax,ebx

:eax레지스터의 값을 ebx의 값으로 만든다.


Inc: 레지스터의 값을 1증가 시킨다.

ex:) Inc eax

:Eax 레지스터의 값을 1증가 시킨다.


Dec: 레지스터의 값을 1 감소 시킨다.

ex:) Dec eax

:Eax 레지스터의 값을 1 감소 시킨다.


Add: 레지스터나 메모리의 값을 덧셈할떄 쓰임.

ex:) Add eax,ebx

:Eax 레지스터의 값에 ebx 값을 더한다.

ex:) Add eax,50

:Eax 레지스터에 즉석값인 50을 더한다.

ex:) Add eax,dword ptr[401F47]

:Eax 레지스터에 메모리 오프셋 401F47의 값을 더한다.



인터넷에서 정리되어있는걸 가져왔습니다.

잘모르시는 어셈문도 있을겁니다^^

posted by bluelimn 2010.12.19 15:33

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class AlphaImage implements AdjustmentListener
{
 private JFrame frame;
 private Canvas canvas;
 private JScrollBar jsp;
 private Image image;
 private AlphaComposite alphaComposite;
 private Label label;
 
 public AlphaImage()
 {
  image = Toolkit.getDefaultToolkit().getImage("1.jpg"); //원하는 이미지
  frame = new JFrame();
 
  jsp = new JScrollBar();
  jsp.addAdjustmentListener(this);
  jsp.setMaximum(265);
  jsp.setMinimum(0);
  image = Toolkit.getDefaultToolkit().getImage("1.jpg");
  label = new Label("alpha = " + jsp.getValue());
 
  canvas = new Canvas(){
   public void paint(Graphics g)
   {   
    alphaComposite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float)jsp.getValue()/255); //alpha값
    Graphics2D g2 = (Graphics2D)g;
    g2.setComposite(alphaComposite);
    g2.drawImage(image, 0, 0, this);   
   }
  };
  frame.add(canvas, BorderLayout.CENTER);
  frame.add(jsp, BorderLayout.EAST);
  frame.add(label, BorderLayout.SOUTH);
  frame.setSize(300,300);
  frame.setVisible(true);
 }

 public void adjustmentValueChanged(AdjustmentEvent e)
 {
 
  if(label != null)
   label.setText("alpha = " + jsp.getValue());
  if(canvas != null)
   canvas.repaint();
 }

 public static void main(String[] args)
 {
  new AlphaImage();
 }
}


'Projects > 얼굴특징점추출' 카테고리의 다른 글

java 투명도(alpha)조절  (0) 2010.12.19
tip : YCbCr to RGB, RGB to YCbCr  (0) 2010.07.04
posted by bluelimn 2008.08.28 09:04

정말 막 만든 것 같다.
그래도 datagridview를 프린트할수 있게 되서 한가지는 얻었다.

그런데 마지막에 세마포어 갯수가 넘친다는 오류는 못잡겠다.
전체를 catch해도 나오지 않는다.. 대체 어디서 해야하는거지?

===========================================================

아무튼 요구사항도 정확치 않고 대략적인 엑셀파일만 받아 시작한 내용
만드는 것보다 Test가 훨씬 힘들다는 사실을 실감했다.
사실 기자재부분은 test해봤지만 시약부분은 어떻게 돌아가는지 확인조차 정확히 안해봤다.
오류가 있는 프로그램을 그대로 보내버린 것은 자존심 상하는 일이지만
지금 그걸 잡고 있자니 시간이 너무 부족하다. 이것도 예상보다 커져서 더 오래 잡고 있었는걸..( 원래 2주만에 끝낼려고 했는데 중간에 피서가는 바람에 일주일이 더 소비되었다.. )

'Projects > 실험실기자재관리' 카테고리의 다른 글

사람들이란..  (2) 2008.09.17
실험실 자재관리  (0) 2008.08.28
아~ MySQL  (2) 2008.08.18
posted by bluelimn 2008.08.21 22:02

DataGridViewCheckBoxColumn chkBillable = new DataGridViewCheckBoxColumn();

chkBillable.Name = "colTimeSheetBillable";

chkBillable.HeaderText = "Billable";

chkBillable.DataPropertyName = "TimeSheetBillable";

chkBillable.ReadOnly = true;

dataGridTimesheet.Columns.Add(chkBillable);

posted by bluelimn 2008.07.08 21:47
오랜 시간이 걸리는 새로운 일과 마주치면?
1. 맨손으로 힘들여 노가다를 한다.
2. 스크립트 언어를 이용해서 그 일을 자동으로 수행하는 툴을 작성한다.
3. 이미 작성되어 있는 툴을 찾기위해 여러 시간을 보낸다.
=== 잠깐동안 툴을 찾아보고 없으면 더이상 미련을 가지지 말고 간단히 스크립트 언어로 자동 수행 환경을 만들도록 하자.

새로운 툴을 발견하면?
원하는 만큼 알게될 때까지 만지작 거리지 말고 관련 문서를 정확하게 읽어보자.
읽으라고 친절히 설명서까지 만들어놨는데 쳐다보지도 않고 혼자 만지작 거리면서 모르겠다고 투정부리는 일은 하지말자.

툴에 구애받지 않는 실력을 가지는 것도 중요하지만 세상에는 툴이 엄청 많다. 똑똑한 툴을 잘 다루는 프로그래머는 더 똑똑한 프로그래머가 된다. C코드를 툴을 사용하지 않고 어셈블리어로 변환하는 사람이 있다면 정신과 상담이 필요하다.

* 어떠한 툴 들이 있는지 알아보고 어디서 구할 수 있는지 확인해보자. 지금 사용하지 않더라도 충분한 보험이 될 수 있다.

툴의 사용법
* 툴로 무엇을 할 수 있는지 알아둬라.
* 어떻게 조종하는지 배워라.
* 어떤 일에 좋은지 알아둬라. (어떤 일을 할 때 사용하면 유용한지)
* 어떤 문제점을 가지고 있는 확인하라.
* 더 많은 툴을 찾을 분명한 루트를 확보하라.
    메뉴얼, 릴리즈 노트, 온라인 지원, 툴 내부의 도움말 파일, man 페이지 등
* 새로운 버젼이 언제 나오는지 알아내라. (최신 버젼이 무조건 좋은 것은 아니다)
===== 하지만 지금 당장 할 일은 툴들의 정보를 공유하는 커뮤니티를 찾는 것일지도

소스코드 편집용 에디터를 선택할 때의 팁
* 포괄적인 문법 컬러링(여러 언어를 지원)
* 간단한 문법 체킹(강력하면 더 좋겠지만)
* 우수한 검색 / 변환 (찾기, 바꾸기 등이 앞뒤로 가능하도록)
* 키보드 매크로 기능(꽤 유용하다)
* 원하는 플랫폼에서 작동하는지(유닉스, 윈도우계열 등 작업환경에서 돌아가야 한다)

TIP 유닉스 계열에서 사용하는 소스 조작 툴
diff : 두 파일을 비교, 서로 다른 부분을 하이라이트 표시
sed : stream editor; 한줄씩 읽어서 변환하는 것을 원칙으로 하는 툴, 항목의 재정렬이나 global 검색이나 치환, 혹은 행 안에 패턴을 삽입할 때도 사용
awk : sed와 비슷한데 이건 text file을 대상으로 작업한다.
grep : 파일 내의 문자패턴을 검색
find/locate : 파일을 찾는다. 이름, 날짜, 그 밖의 기준을 가지고 검색
wc : 단어와 문자를 세는 일을 한다
sort : 원하는 정렬 기준에 맞추어 재정렬한다
paste, join, cut 등 유용한 것들 꽤 많다. 유닉스의 기본 철칙은 작은 툴들이 모여서 큰 작업을 한다는 것이다.

좋은 프로그래머
* 지루한 일을 반복하기 보다는 적절한 툴의 사용 방법을 배우려고 한다.
* 여러가지 toolchain의 모델을 알아두고, 각각을 힘들지 않게 사용할 수 있도록 한다.
* 편의를 위해 툴을 사용하지만 툴의 노예가 되진 않는다.
* 사용하는 모든 것을 교체 가능한 유용한 도구(툴)로 본다

나쁜 프로그래머
* 몇가지 툴의 사용법을 알고있지만, 모든 문제를 툴에 맞추어 생각하려고 한다.
* 새로운 툴을 배우기 위해 시간내는 것을 꺼려한다.(익숙한 것만 하려고 든다.)
* 어떤 개발환경을 사용하기 시작하면, 그것을 종교처럼 받들고 절대 다른 것의 사용을 시도하려고 들지 않는다.
* 가치있는 새로운 툴을 발견해도 자신의 툴박스에 추가하지 않는다.
posted by bluelimn 2008.06.26 22:00

에러나 예외를 일으킬 때 주의
* 청소는 했는가? - 리소스 누출(동적할당 등), 자료들의 모순상태 등을 확인. 어쩔 수 없이 제대로 청소되지 않는 상황이라면 반드시 기록을 남겨둬야 한다.
* 에러정보에 부적절한 내용을 담지 마라
* 올바른 exception을 사용 - 에러나 예외가 아닌 특이한 값을 return하지 마라. 즉 올바른 자료랑 예외상황을 섞어서 사용하지 말란 말이다.
* 정상적인 실행과정 중 절대 일어나지 말아야 할 진짜 프로그래밍 에러를 잡으려고 한다면 assertion의 사용을 고려해보라. 하지만 assertion은 완성본에 남아있으면 안된다. exception을 활용하는 것이 더 나을수도 있다.
* 사람들이 무시하지 않도록 만들어라.

일반적인 에러 체크 목록
* 함수의 모든 파라미터를 체크
* 관심 있는 실행 지점에서 불변조건(invariant)이 만족하는지 검사
* 외부에서 들어온 값은 사용하기 전에 모두 유효성 검사를 해라. 특히 파일로부터 얻어오는 자료와 사용자가 입력하는 자료는 유효성검사가 꽤 중요하다.
* 시스템 호출과 함수 호출에 있어서는 가능한 모든 호출에 대해서 리턴 상태를 체크

에러 관리하기
* 에러의 원인이 될만한 일은 피해라 - 리소스 할당 에러는 충분한 리소스를 미리 예약(pool)하면 피할 수 있다.
* 프로그램이나 루틴이 비정상적인 상황에서 어떤 동작을 할 것이 예상되는지 정하라(GIGO: Garbage In Garbage Out)
* 자신의 프로그래밍 습관을 체크 : 에러 처리 코드를 나중으로 미루지 마라.

실패 가능성이 있는 코드를 작성할 때는 에러 감지 코드와 에러 치리 코드도 함께 작성하라.

posted by bluelimn 2008.06.24 23:43

에러 처리하기

에러를 처리하기 전에 알아야 하는 것들:
* 에러가 어디서 나왔는가
* 당신을 무엇을 하려 했는가(무엇을 하다가 에러가 발생했는가)
* 일이 왜 잘못 되었나
* 에러가 언제 일어났나
* 에러의 심각성
* 에러를 고치는 방법

에러를 발견했을 때
1. logging (로그기록)
2. report(보고) (임베디드의 경우 보고대신 스스로 처리해야 할 때도 있다)
3. recovery(복구)
3. ignore(무시)
4. propagate(전파) : # 똑같은 에러정보를 전파, # 재해석 후 새로운 메시지를 전파

코드구현 테크닉

좋지않은 if중첩의 예(2)..


중첩을 피한 if문(1)..


중첩을 피한 if문(2)..

posted by bluelimn 2008.06.14 14:00

오류의 발생은 원인에 따라 세가지로 요약할 수 있다.
사용자 에러 : 정확히 다 잡기가 어려워 배포 후에도 발생할 수 있다.
프로그래머 에러 : 나와서는 안되는 에러
예외상황 : 프로그래머가 정상적으로 작성했고 사용자도 정상적으로 사용했다. 하지만 네트워크 연결이 이상할 수도 있고, 하드디스크나 메모리에 용량이 부족할 수도 있고 갑자기 전원이 나갈 수도 있다.

에러를 처리하는데 중요한 몇가지를 먼저 알아보자.
1. 발생은 하위 콤포넌트, 처리는 호출자(caller) : 즉 누군가 일을 잘못하면 시킨 사람이 책임진다는 뜻이다.
2. 잘못이 있을 때는 에러를 발생시켜야 한다.(그냥 뻗도록 해서는 안된다.)
3. 보고도리 수 있는 모든 에러를 감지한다.
4. 감지된 에러를 적절하게 처리한다.
5. 처리할 수 없는 에러는 다른 곳으로 전파한다.
에러 처리는 exception 처리와 거의 같게 취급하면 될 것 같다.

에러 리포트 메커니즘 ( 오류를 알리기 위한 방법 )
1. return값 : return되는 값이 boolean으로 함수의 성공, 실패를 알려주는 용도라면 적당하게 작동한다. 단, 에러의 종류는 알 수 없다. return 값이 필요한 함수에서 오류도 함께 return의 값으로 알려주려고 시도하는 경우도 있다. 가능은 하지만 권장하지 않는다. 그래도 꼭 해야 하겠다면 몇가지 방법이 있다.
  * return값을 좀더 복잡하게 만들어 원하는 결과와 오류정보를 둘다 가지고 있는 구조체나 객체를 return하는 방법 : 네트워크에선 가끔 이용되지만 일반적인 프로그래밍에선 사용되는 경우가 거의 없다.
  * 참조(reference)를 이용하여 파라미터를 통해 보내는 방법 : 이또한 보기에도 좋지 않고 직관적이지도 않다.
  * 오류의 범위를 지정 : return값이 0이상의 값만 의미가 있을 때(count등) 음수를 오류로 처리하거나 참조나 포인터일 경우 NULL을 에러로 처리하는 것이 가능하다.
어떤 방법을 사용하건 지저분해진다. 에러를 발생시키는 것도 어렵지만 처리도 지저분해진다.

2. 에러 상태 변수 : 특수한 값들을 에러로 define해놓는 방법이다. C언어에서 가끔 사용되는데 결국 이런 것도 전역으로 사용되며 프로그램이 실행되는 동안 내내 메모리에 올라가 있는 값이기 때문에 많으면 좋지 않다. 게다가 파일이 여러개면 제대로 확인하기도 어렵다.

3. exception(예외처리)
에러처리를 위해 만들어진 구문으로 throw-catch, throws구문을 이용하여 에러를 handler에게 보내는 방법이다. 에러처리 전문 문법이기 때문에 가장 깔끔하고 직관적이지만 모든 언어에서 지원해주는 것은 아니다. C언어에는 없고, C++, JAVA, .NET등에는 있다.
 * 종결모델(termination model) : 헨들러가 처리한 부분부터 다시 실행(C++, .NET, JAVA)
 * 재개모델(resumption model) : 오류가 발생한 부분으로 돌아가서 다시 실행
예외처리는 안전성에 몇가지 단계가 있다.
==== 기초보장(basic guarantee)
   exception이 발생해도 메모리 누수가 없도록 해야한다. 동적 할당을 받았다면 반드시 확인해보자.
==== 강력한 보장(strong guarantee)
   exception이 발생해도 프로그램의 상태는 아무것도 바뀌면 안된다. 전역변수도, 지역변수도 객체도 그 값을 그대로 유지하고 있어야 한다.
==== no throw(nothrow guarantee)
   operation이 exception을 던질 수 없도록 만든다. 3가지 보장 중 가장 강력한 방침인데 예외상황을 발생시키지 않는다. 가장 중요한 것은 소멸자에서 exception을 던지지 않는다는 보장이 있어야 한다는 것인데 객체지향언어에서 소멸자는 객체의 생명이 다할 때 자동으로 호출되며 exception이 발생했을 때도 스택이 풀리면서 호출된다. (C#에서는 소멸자에서 exception을 던지는 것이 의미가 있으며 그것을 인정한다)

4. signal
극단적인 에러 리포트 메커니즘으로 전기 신호로 에러를 발생시키고 시그널 핸들러를 설치해야 한다.

=======================================================================
exception을 무시하더라도 감지하는 코드는 만들어둬야 한다.
그래야 나중에 코드를 봤을 때 exception의 가능성이 있다는 것을 알 수 있다.
=======================================================================

posted by bluelimn 2008.06.11 21:26

일관성
코멘트도 일관성을 유지하는 것이 좋다. 보기 좋은 떡을 만들라. 누가 뭐래도 코멘트는 사람에게 보여주기 위해 작성하는 것이 아닌가!

뚜렷한 블록 코멘트
에디터에서 색이 다르고 굵게 표시되는 경우가 많지만 흑백으로 프린트해서 봐야 할 수도 있다.(특수한 경우를 생각하지 말고 일반적인 것을 생각하라!)
코멘트의 시작과 끝은 들여쓰기 등으로 다른부분과 구분을 지어야 한다.

/*
  * 좋은 예시의
  * 블록 코멘트
  * 알아보기가 쉽다.
*/

/* 나쁜 예시의
          블록 코멘트
알아보기 어렵다.
*/


1행 코멘트
코드 중간에 들어가지 않도록 해야 한다. 만약 코드 중간에 한줄을 잡는다면
코드의 들여쓰기와 맞춰 알아보기 쉽도록 해야한다.
행 끝에 따로 띄어서 코멘트를 작성하는 것도 괜찮다.
오른쪽에 코드로부터 분리하여 코멘트들을 작성하는 것인데 알아보기는 쉬우나 코드를 수정할 때 간격을 다시 맞춰야 하고 코드가 긴 행을 만나면 화면 밖으로 나가버릴 가능성도 있다.

일반적인 약속(관례)
코멘트는 코드의 위쪽에 쓰인다. 즉, 코멘트가 먼저 나오고 그에 해당하는 코드가 나온다.
코멘트가 단락의 시작으로 여겨지도록 한다.

유지보수가 저렴한 스타일을 선택
/***********************************
*******     모양은 이쁘지만    ********
*******  간격맞추기가 어렵다  ********
***********************************/

게다가 스페이스를 사용하느냐 탭을 사용하느냐에 따라 모양이 다르고 탭을 사용하는 경우 탭의 너비설정이 다르면 또 모양이 달라진다. 쓸데없는 곳에 열정을 낭비하지 말자.

방파제 코멘트
가끔 코멘트가 코드 사이에 방파제 역할을 하는 경우가 있다.
프로그래머는 중요한 코멘트를 특별하게 표시할 필요가 있는데 한 소스파일 안에 여러개의 클래스가 구현되어 있는 경우, 중요 섹션을 구분하기 위해 방파제 코멘트를 사용한다.
/***********************************
* 방파제 코멘트
* 가끔 필요할 때가 있다
***********************************/

좀 전에 함부로 사용하지 말라고 한 것과 비슷한 모양이지만 눈에 띄는 것이 중요하지 ASCII예술을 통해 이쁘게 하지 마라. (ASCII예술이란 특정한 상황에서 띄어쓰기 등으로 화면에 보이는 것을 미술적으로 표현하는 것을 말하는 듯하다.)

플래그
다른 사람의 코멘트를 읽을 때 약속된 플래그를 알아두는 것이 좋다.
// XXX      : 문제를 일으키는 코드나 재작업이 필요하다는 표시
// FIXME   : 고장 난 부분
// TODO    : 누락된 기능(나중에 돌아왔을 때 추가해야 할 기능)
TODO를 사용하기 보다는 exception을 던지는 것이 훨씬 매끄럽다. 하지만 다른 사람이 해놓은 것을 알아볼 필요는 있겠지.
하지만 플레그를 두려워 하지 마라. 코드를 마무리하기 전에 플레그를 검색해보면 된다.

파일헤더 코멘트
앞에서도 이야기 했던 내용이다. 모든 소스 파일에는 헤더 코멘트로 시작해야 한다.

불필요한 코멘트
코드를 수정할 때 코멘트를 달지마라.
어떠한 내용을 무엇때문에 어떻게 고쳤다..라고 코멘트를 다는 것은 불필요하며 지저분하다. 필요한 경우 결함 추적 시스템(fault-tracking system)을 이용해 결함을 찾고, 파일의 예전 리비전을 끄집어내어 조사할 수 있다. 이러한 불필요한 코멘트는 오히려 코드를 어지럽힌다.

코멘트 유지보수
바로 위에서 코드를 수정할 때 코멘트를 달지 말라고 했다. 그렇다면 코드를 수정할 때는 그냥 넘어가면 되는 것인가? 절대 아니다.
코드를 수정할 경우 그와 관련된 코멘트를 모두 확인하고 보수해야 한다.

코멘트를 의심하라
코드를 코멘트로 막아두는 경우가 있다. 일시적인 경우지만 때로는 오래갈 때도 있다. 이런 경우 적당한 설명을 함께 두거나 아예 코드 자체를 지워야 한다.
코멘트가 있더라도 코드의 수정과 함께 유지보수가 되지 않은 코멘트일 수 있고 작성한 사람이 잘못 작성했을 가능성도 있다. 항상 코드를 신뢰하고 코멘트는 의심해야 한다.


-----------정리-------------
* 소량의 코멘트를 작성하라
* 왜(why)에 대해 작성하라
* 코멘트보다 코드의 작성에 집중하라
* 코드와 함께 유지보수하라
& 코드의 내용을 중복하지 마라
& 자신만 알아보는 코멘트를 작성하지 마라

posted by bluelimn 2008.06.05 15:03
코멘트(주석, comment)란?
컴퓨터가 보는 것이 아니다. 대상은 사람이다.(작성자 자신도 포함)
C언어는 /* 주석 */ 으로 여러행에 걸쳐 주석을 넣을 수 있다.
C++, C99, C#, Java에서는 여기에 // 뒤에 한줄로 된 코멘트가 추가된다. 내가 알기론 그렇데 교수님이 수업할 때 학생 중 하나의 말에 따르면 C언어 표준의 최신 정의를 보면 C언어에 //로 된 한줄짜리 코멘트도 인정했다고 한다.
언어마다 comment를 정의하는 문법은 조금씩 다르지만 다들 가지고 있다.
@ comment, #comment, $comment, <! comment --> 등 다양하지만 웬만한 언어는 모두 코멘트를 작성할 수 있도록 지원해준다.
코멘트는 코드와 가장 가까이(내부)에 있는 문서로 코드를 읽어갈 때 방향을 잃지 않도록 도와준다.

코멘트는 적게 사용하는 것이 좋다?
코멘트의 양이 많을수록 코드를 읽기 어려울 수도 있다. 잘못된 코멘트는 심각한 오해를 불러일으키며, 잘못된 코멘트가 아니더라도 양이 많고 위치가 뒤죽박죽이면 읽기 힘들어진다.
코멘트는 오해의 소지가 있는 곳, 읽기 힘든 곳, 알아보기 힘든 곳에서는 반드시 있어야 한다. 하지만 잘 만들어진 코드는 논란의 여지가 없고 알아보기 쉬운 코드이므로 코멘트가 그만큼 줄어든다. 많은 코멘트가 필요없는 코드를 작성하기 위해 시간을 투자하자!

어떻게(How)가 아니라 왜(Why)를 기술하라
코멘트의 기본이다. 그리고 코멘트에서 가장 중요한 부분이다. 어떻게 돌아가는지는 코드를 보면 충분히 알수 있다. 왜 이런 코드를 작성했는지에 대한 것을 적어라. 명심히라. 코멘트는 How가 아니라 Why를 기술해야 한다.

코드를 묘사하지 마라
How를 기술하지 말라는 것과 같은 내용이다. 코드에 있는 사실을 다시 코멘트로 만들지 마라

코드를 대신하지 마라
코멘트가 길어지고 있다면 코멘트를 잘 쓰기보다는 코드를 알아보기 쉽게 고치도록 하자.
코멘트의 내용이 지나치게 중요하다면 코드는 수정되어야 한다.

유용성을 유지하라
- 의외의 것을 기록하라
    일반적이지 않은 코드, 특이한 녀석은 반드시 코멘트를 달고 뻔한 코드는 코멘트를 달지 마라. 특이한 녀석은 적을수록 좋다.
- 진실을 말하라
    잘못된 코드는 오히려 심한 오해를 불러들인다. 코드를 수정하면서 코멘트는 가만히 두는 경우 이런 문제가 발생할 수 있다. 코드를 수정할 때 코멘트도 잘 봐야 한다.
- 가치 있게 만들어라
    농담, 비속어, 이모티콘, 장난, 암호 금지... 장난치지 마라. 당신은 지금 얼마나 오래갈지 모르는 소스를 만들고 있다.
- 명료하게 만들어라
    구체적이고 정확하게 써라. 누군가 당신의 코멘트를 읽고 무슨 뜻인지 몰라 어리둥절해지면 당신은 코드를 악화시킨 것이다.

블록의 끝을 무조건 //end of if( a < 1 ) 이런 식으로 하는 것 나쁜 습관이란다. 난 이렇게 하려고 습관들이고 있었는데..
왜냐하면 블록은 한 페이지 안에 들어와야 하고 알아보기 쉽게 되어있어야 하기 때문이란다.

코멘트를 잘 달기보다 이름을 잘 짓는것에 더 투자하라.
posted by bluelimn 2008.05.30 22:22

파일 헤더를 제공하라
사소하지만 꽤 중요하다. 난 지금까지 제대로 지키지 않았다. 앞으로는 잘 하도록 노력해야겠다. 대부분의 회사에서는 법률적인 이유로 모든 소스 파일에 가시적인 저작권 공지를 포함시키도록 의무화하고 있단다.
/*************************************
* 파일 : FileName.java
* 목적 :
* 알림 : 저작권표시
*************************************/

에러를 적절하게핸들링하라
에러는 발생한 곳과 가까운 곳에서 처리하는 것이 좋다. 에러가 발생하면 어디서 왔는지, 에러의 이유가 무엇인지, 에러가 발생한 것은 무엇을 의미하는 것인지 알기 쉽도록 해라.(어떻게? 잘~)

의미 있는 코멘트를 작성하라
학교에서 처음 프로그래밍을 배우면서 코드를 작성하고 발표수업이 있을 때 모든 문장에 코멘트를 달도록 강요받은 기억이 있다. 코멘트가 너무 많은 코드는 오히려 보기 불편하다. 가능하면 코멘트가 필요없도록 작성하되 그러고도 남아있는 부분에 대해서는 적절한 분량의 코멘트를 추가해야 한다.
* 파일헤더, 함수의 설명, 변수에 대한 설명은 가능하면 생략하지 마라.


문서화의 여러가지 방법


문학적 프로그래밍(프로그램을 작성하지 말고, 문서를 작성하라. 소설처럼 써라.)
장점

* 문학적 프로그래밍은 문서작성에 강점을 둔다.
* 문서가 가까이 있으므로 업데이트할 때 문서도 함께 업데이트 하기 쉽다.
* 전체 코드베이스에 대해 단 하나의 문서만 존재한다는 사실이 보장된다.(코드 자체가 문서기 때문)
* 일반적으로 코멘트에 쓰이지 않는 항목도 문서화하도록 유도한다.(사용된 알고리즘에 대한 설명, 코드가 올바르다는 증명, 그렇게 설계하게 된 결정의 정당성.)
* 유지보수에서 빛이 난다.
단점
* 코드가 아니라 문서 전체를 작성해야 하므로 대부분의 프로그래머들이 힘들고 귀찮아 한다.
* 또 하나의 컴파일 단계가 필요하고, 그것이 작업 속도를 느리게 만든다.(아직 바로 컴파일해줄만한 툴은 없단다. 당연하지!)
* 정말 문서화가 필요하지 않은 부분까지도 문서화하게 될지도 모른다. 또는 일부를 문서화하지 않게 될지도 모른다. 귀찮으면 아예 하지 않는 것이 좋다. 이도저도 아니면 안된다.
* 프로그램 잘 짠다고 글도 잘쓰는 것은 아니다. 훌륭한 프로그래머라고 해서 반드시 유능한 문학적 프로그래머가 되는 것은 아니다.


문서화툴
문서화를 도와주는 툴이 많이 있다는 말이다. 책에서는 Javadoc를 예로 들었는데 이는 다음과 같은 일을 도와준다.
 * 저작권 정보를 명시한다
 * 생성일자를 기록한다
 * 정보를 상호 참조시킨다
 * 오래된 코드에 deprecated라고 표시한다.(오래됐다고 바꾸라고 권장한다는 뜻)
 * 빠른 참조용의 짤막한 개요(synopsis)를 제공한다
 * 함수 파라미터 각각에 대한 설명을 제시한다
javadoc, C#의 NDoc와 Doxygen(www.doxygen.org)등이 있단다.
장점
* 코드의 문서화와 업데이트를 촉진
* 컴파일할 수 있는 코드를 위해 별도의 단계가 필요하지 않다(문학적 프로그래밍과의 차이)
* 비교적 자연스럽게 보인다.
* 문서화 툴은 풍부한 검색, 상호 참조, 코드 아웃라인 기능을 지원
단점
* API의 문서화에만 정말로 유용하고, 내부 코드의 문서화에는 일반 코멘트를 사용해야 함
* 소스 파일을 훑어보고 개략적인 내용을 파악하기 어렵다.(이런 건 문학적 프로그래밍이 한 수 위)
주의
* public 항목에 대해서는 하나 또는 두 개의 문장으로 구성된 설명을 작성하라. 쓸데없이 주절주절 늘어놓지 말란 말이다.
* 변수나 파라미터가 어디에 사용되는지 분명하지 않으면 문서화하라. 단 이름만 보아도 확실하게 알수 있으면 문서화하지 마라.
*함수 파라미터 중 어떤 것은 입력에 사용되고 어떤 것은 출력에 사용된다면, 그런 사실을 파라미터 설명에 명확히 기술하라
* 함수의 전제조건, 후행조건, 발생할 수 있는 exception, side effect를 모두 문서화 하라.

생각해보니 2학년 때 이현아교수님이 문서화 툴에 대해 언급했었고 임은기 교수님도 권장한 적이 있다. 다만 귀찮아서 사용하지 않았다. 잠시 알아본 적도 있었지만 귀찮아서 사용하지 않았다. 문서화 툴은 형식이 일정한 것이 아니라 툴 마다 다르기 때문에 필요하다면 실무에서 사용되는 공통된 것을 이용하면 될 것 같다. 사용법이 그리 어렵지 않으니 그때그때 필요한 것을 배우면서 사용할 수 있다. 문서화 툴에 의존하기보다는 필요한 정보는 코멘트로 달아두는 습관을 기르는 것이 더 도움이 될 것 같다.

+ 파일에는 헤더를 유지 (파일명, 목적, 저작권 [, 특이사항])
+ 함수에도 헤더를 유지 (parameter, return value, 목적)
+ 변수는 이름만으로 명확한 것이 아니면 반드시 설명(객체형식이라면 이름이 확실해도 설명을 붙여두는 것이 좋다.)

posted by bluelimn 2008.05.29 00:35

유클리드 호제법 : 기원전 300년경 기하학자 유클리드가 주장하여 그의 이름을 딴 공식으로 알려져 있다.
두 자연수 A,B에 대하여 A를 B로 나누었을 때 몫을 Q, 나머지를 R이라고 하면(A = BQ+R)
A,B의 최대공약수는 B,R의 최대공약수와 같다.
<증명> A,B 둘의 최대공약수 G
A = aG, B = bG (a,b는 서로소)
(A = BQ+R, B = bG 이므로)
bGQ+R = aG
=> R = (a - bQ)G
--------------------------
A = aG
B = bG
R = (a-bQ)G
그러므로 A,B의 최대공약수와 B,R의 최대공약수는 G로 서로 같다.

========================================================================
#include <stdio.h>
unsigned int gcd(unsigned int valuer1, unsigned int value2);
unsigned int lcm(unsigned int value1, unsigned int value2);

int main()
{
    unsigned int value1, value2;
    printf("자연수 2개를 입력하시오 : ");
    scanf("%d %d", &value1, &value2);
    printf("최대공약수 : %d\n", gcd(value1, value2));
    printf("최소공배수 : %d\n", lcm(value1, value2));
    return 0;
}

반복문사용 gcd..


재귀호출사용 gcd..


int lcm(int value1, int value2)
{
        int temp;
        temp = gcd(number1, number2);
        return (number1/temp)*number2;
}

======================================================================
위의 소스는 우선 돌아가는 것 같지만 약점이 있다.
입력값을 전혀 체크하지 않는다는 것! 만약 자연수를 입력하지 않는다면 문제가 발생할 가능성이 크다.
0 0을 입력한다면? 만약 수를 입력하지 않고 문자를 입력해 버린다면?
간단히 오류체크를 추가해서 main을 바꿔보자.

int main()
{
    unsigned int value1, value2;
    do{
        printf("자연수 2개를 입력하시오 : ");
        scanf("%d %d", &value1, &value2);
    }while(value1 <= 0 || value2 <= 0);
    printf("최대공약수 : %d\n", gcd(value1, value2));
    printf("최소공배수 : %d\n", lcm(value1, value2));
    return 0;
}

간단히 do-while을 사용해서 자연수가 아닌 정수(0,음수)는 걸러주도록 했다.
숫자 이외의 값이 입력되는 경우는 찾아보기 쉽게 다른 글로 다시 써야겠다.

posted by bluelimn 2008.05.21 19:46

Welcome to Microsoft DreamSpark

Professional Developer and Designer tools for students at no charge



DreamSpark is simple, it's all about giving students Microsoft professional-level developer and design tools at no charge so you can chase your dreams and create the next big breakthrough in technology - or just get a head start on your career.

Who can get this right now?
We are kicking this off in 11 countries/regions, giving DreamSpark to millions of students in the United States, the United Kingdom, Canada, China, Germany, France, Finland, Spain, Sweden, Switzerland and Belgium. If you are not residing in one of the countries listed keep checking back, we will be adding more countries throughout the year.

Does that mean that I might not get in?
Possibly, if you are not residing in one of the countries listed, not attending an accredited university or not a member of one of the student organizations that we're connected with. But keep checking back, as we're working on adding more ways to verify your student status all the time.

What do I have to do to get this software? Not much really, just select a product and follow the steps below.

  • Sign In with your Windows Live ID. If you don't have one, go get one here. Pretty basic stuff.

  • Get verified as a student. The system is linked to schools and organizations around the world that can confirm student status. Simply choose your country and school, enter your info and hit submit.

  • Download your products. Now remember these are professional tools. This means they are pretty big files so make sure you have the bandwidth and space to bring them to your machine. We support the latest versions of both Internet Explorer and Firefox for your download.
 

Microsoft® Expression® Studio

Microsoft® Expression® Studio takes your creative possibilities to a new level. The professional design tools and innovative technologies in Expression Studio give you the flexibility and freedom to bring your vision to reality—whether you are designing standards-based Web sites, rich user experiences on the desktop, or managing digital assets and content. Expression Studio includes the following products:


When you download and save this product to your computer, it will be in the form of an ISO file. The downloadable ISO file must then be placed onto a CD/DVD or mounted using a virtual drive before installation can occur. To get detailed instructions on how to open the ISO file and install this product, click here.
 
 
 

XNA Game Studio 2.0

XNA Game Studio 2.0 – Microsoft XNA Game Studio 2.0 is a set of tools that allow students, hobbyists and independent developers to build games for both Microsoft Windows and Xbox 360. XNA Game Studio 2.0 is based on the .NET Framework and includes custom managed code libraries, Xbox Live Support, and Games for Windows Live support to make multi-player game development easier.

XNA Creators Club 12-Month Trial Subscription – Coupled with XNA Game Studio 2.0, the XNA Creators Club 12-Month Trial Subscription opens up video game development to untapped creative minds, enabling anyone to affordably build and play their amazing game ideas on Xbox 360™ systems for the first time ever. The access key below grants access to a 12-month trial subscription that provides aspiring game developers the ability to develop games for their Xbox 360 without having to pay the $100 yearly subscription.
 
 
 현재 아시아권에서는 중국만 서비스 중이라, 우리나라는 다운로드 받을 수 없다.
 우리나라는 9월부터 서비스를 제공한다고 한다. 그리고 정말 대학생만 받을수 있다.

[출처] Microsoft Dreamspark- 마이크로소프트 드림스파크|작성자

11개국 국가에 대학생들..그리고 고등학생까지 확대하고 있단다.
========================================
만약 ISIC 국제학생증을 가지고 있다면 지금 바로 개발툴을 다운로드 할 수 있다. 현재 배포 되고 있는 개발툴은 비주얼 스튜디오 2005, 2008 / 윈도우즈 2003 서버 에디션 / SQL 서버 2005 / 익스프레션 스튜디오 / XNA 게임 스튜디오 2.0 이다. 개인적으로는 조만간 발표될 익스프레션 스튜디오 2도 조속히 배포되었으면 하는 바람이 있다. (부족한 실버라이트 인프라를 생각하면 아마도 공개될 것 같다.)

아마도 개발툴에 있어 오픈소스도 너무 많고 이클립스, JAVA진영에 많은 위협을 받아 유저들을 잘 키워서 잡아먹겠다는 생각이 아닐런지.. 우리 돈 많으니 앞으로의 고객들에게는 우선 안받아도 된다는 생각!
쉽게 말해서 배우는건 MS제품으로 배우고 실무에 나가서 팔아먹을 위치에 오르면(그땐 학생이 아니겠지) 돈주고 사라는 말이다.
그럼에도 복학하자마자 ISIC인증 받아서 다운받아버릴테닷!!

posted by bluelimn 2008.05.14 23:03

의미있는 이름을 사용하라.
변수, 타입, 파일, 함수등 모든 것들의 이름은 의미가 있는 것이어야 한다. x,y,z,a,b,c같은 이름들은 나중에 자신이 봐도 정확히 이해하기 어려울지도 모른다.

함수 작성 시 유의
- 하나의 함수는 하나의 동작! (동사로 이름짓는 것이 원칙)
- side effect를 최소화하라(side effect란 함수가 실행되는 도중에 외부에 있는 값이나 상태를 바꾸는 것을 말한다.)
-  짧게 만들라. 한 화면에 모두 들어갈 수 있도록 하되 코드를 짧게 만들기위해 무리하게 줄이지는 마라.

제약을 많이 가하라.
- const등을 이용해서 값이 바뀌면 안되는 것들은 모두 상수화해라.
- 양수만 가진다면 unsigned type을 사용하라. 귀찮다고 그냥 넘기는 경우가 많다.
- 몇가지 선택사항이 있다면 열거형식(enum)을 활용하라.
(가끔 생각하는데 boxing과 unboxing에 대한 것, 혹은 casting에 관한 것이 이러한 제약들과 겹칠 경우 어떻게 해야 하는가..하는 문제다. unsigned type의 변수를 선언했는데 signed형식을 parameter로 사용하는 method를 이용해야 할 경우 강제형변환(type casting)이 필요하다. 이러한 형 변환이 많이 사용될 때는 그냥 처음부터 signed로 하는게 좋지 않을까?)

마법의 수를 피하라.
코드내에 숫자가 들어가는 경우를 magic number라고 한다. if(counter == 76)과 같은 코드를 만나게 되면 76이 무엇을 뜻하는지 모르게 된다. #define과 같은 코드를 사용해서 문자상수를 사용할 수도 있고 상수를 선언해서 사용할수도 있다.
더욱 심한 경우를 초보자들이 많이 사용하는데 문자를 구분할 때 숫자를 적어버리는 경우가 있다. 이러한 경우는 C언어에 한해서 많이 나타나는 상황인데 특정한 문자인지 확인하기 위해 그 문자의 ASCII코드값을 적어버리는 경우가 있다. source를 유니코드를 사용하는 언어에 그대로 사용할 경우가 생길지도 모른다. 코드값이 다른 상황이 생길지도 모른다. 문자와 상수가 비교되지 않는 컴파일러를 만날지도 모른다.
코드에 숫자를 직접 넣어버리는 것은 피하도록 하자.

연관된 정보는 묶어라.
프로젝트의 크기가 커질수록, 코드의 길이가 길어질수록, 함수와 클레스가 많아질수록 분류의 중요성은 더욱 강조된다. 큰 물에서 놀고싶으면 애초에 큰 물에서 하는 습관을 들여놔야 한다.
- 한 콤포넌트를 위한 API는 한 파일안에 표현해야 한다.
- namespace나 package등을 이용하여 그룹화하라. 관계가 있는 상수들은 enum으로 정의하라.

posted by bluelimn 2008.05.13 10:29
외부 문서의 지원이 필요한 코드는 작성하지 마라. 그런 코드는 취약하다. 코드 자체만으로 명료하게 읽히도록 만들어야 한다.
 - 외부 문서가 필요한 코드의 경우 수정 될 때마다 외부 문서를 같이 수정해야 한다. 처음 작성되었을 때 어떻게 되었는지 알 필요가 있는 경우 이러한 문서 작업은 더욱 복잡해 질 것이다. 큰 프로젝트를 작업하는데 이렇게 진행하면 힘들어서 제대로 진행하질 못한다.
 - 그렇다고 지나치게 상세한 코멘트(주석)로 코드 자체의 내용을 가리는 것도 옳지 않다. 코드만 보고도 쉽게 알 수 있는 곳이라면 코멘트를 자제하자. 어차피 코드만 보고 이해하기 쉽도록 만드는 것이 목표이니 코멘트는 필요없는 것인가? 코멘트가 필요한 곳과 작성요령은 나중에 다시 다룬다.

코드가 명료해지면 실수할 가능성이 적어지기 때문에, 코드의 품질이 높아지고, 유지보수 비용이 줄어든다. (가독성을 높이는 것이 최대 목표라고 생각해라.)

가끔 자신이 만든 소스를 다른 사람들이 쉽게 알아보지 못하는 것에 대해 쾌감을 느끼는 변태들이 있다. 단점은 그런 변태들과 같이 일하고 싶어하는 사람이 적다는 것이다.

읽기어려운코드..


같은 일을 하는 함수다. 어떻게 보이는지 감상해보자.

스스로 문서화된 코드..


중요한 것은 짧은 코드를 작성하는 것이 아니라 다른 프로그래머가 봤을 때 쉽게 읽을 수 있고 명확한 코드를 작성하는 것이다.

if문의 함정에 조심하라!
 - 이건 책에서 강조하는 것이 아니라 내가 강조하는 내용이다. 책에서는 if-then-else 구조를 작성할 때 "정상"인 경우가 "에러"인 경우보다 항상 앞에 나오거나 그 반대가 되도록 하라고 권한다.

내가 권하는 방법은 if문은 가능한 처음부터 사용하지 말라는 것이다. 초보 프로그래머가 쉽게 작성하는 코드는 많은 문제를 if, else문으로 처리하려고 들고 if문 내에 전체 코드를 다 넣으려고 한다. 특히나 if문으로 오류처리를 하면서 전체 코드를 다 집어넣는 경우 처리할 오류가 많아질수록 중첩수준이 깊어진다.

그래서 일단 이론적으로 올바른 입력이 있을때(아무런 오류처리도 필요없을 때)의 코드를 먼저 작성하고 오류처리는 if문으로 나중에 추가하라고 권한다. 불필요한 경우 else문도 절대 사용하지 말것을 권한다. 이것이 올바른 것인지는 모르겠지만 중첩의 깊이가 적을수록 코드를 읽을 때 생각할 것이 줄어든다는 믿음에는 변함이 없다.
2008.05.02 16:26

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

posted by bluelimn 2008.05.01 11:56

#include <stdio.h>

unsigned long factorialUsingRecursion(unsigned long n);
unsigned long factorialUsingLoof(unsigned long n);

int main(void)
{
        printf("10! = %lu\n", actorialUsingRecursion(10));
        printf("10! = %lu\n", factorialUsingLoof(10));
        return 0;
}

// 재귀호출을 이용한 factorial계산
// 종료조건(if)을 가장 먼저 적어주는 것에 유의
// 재귀호출은 어떻게 돌아가는지가 중요한 것이 아니라
// 어떤 수식을 그대로 옮겼느냐만 생각하면 된다.
unsigned long factorialUsingRecursion(unsigned long n)
{
        if(n <= 1) return 1;
        return(n*factorial(n-1));
}

unsigned long factorialUsingLoof(unsigned long n)
{
        unsigned long result, i;

        result = 1;
        for(i=2; i<=n; i++)
        {
                result = result * i;
        }
        return result;
}

posted by bluelimn 2008.04.11 19:17
변수 :
- 명사로 이름 짓는다. ( 변수는 data 자체를 가리키는 경우가 많다.)

- 명사로 사용할 수 없을 땐 명사화된 동사를 사용(ex: count)

- 변수이름의 첫글자는 영문 소문자로 시작

※ 헝가리언 노테이션 : type에 관한 정보를 이름에 포함시키는 방식으로 멤버변수의 경우 m_으로 시작하고, 포인터의 경우 이름 뒤에 _ptr... 뭐 이런 식의 작명법을 말한다. 이 책에서는 그러한 방법을 따르지 말라고 경고하고 있다. Win32와 MFC의 라이브러리에서 헝가리언 노테이션을 따르는 것이 대중적인 사용의 주된 이유지만 type에 관한 정보는 선언할 때 보는 것으로 충분하며 그러한 것들을 표시해줘야 할 정도라면 함수의 크기가 너무 커서 불편하다는 것이므로 나누라고 권한다.
단, type정보가 아니라 기능에 대한 정보라면 이름에 포함하는 것이 맞다. (index기능을 하는 변수를 idx_로 시작하기도 한다.)

※ 머리글자 조합 : 각 단어의 머리글자를 따서 이름짓는 방식이다. (예를 들어 SomeTypeWithMeaningfulNaming 라는 이름이 있다면 stwmn으로 줄이는 것이다. 일반적으로는 사전에 나오는 내용으로 구성하는 것이 원칙이다. 하지만 변수가 좁은 범위에서 사용된다면 너무 긴 이름 대신 짧은 이름으로 대치하고 주석을 달아두는 것도 좋다.


함수:
- 동사로 이름 짓는다.

- be, do, perform등과 같은 의미없는 동사의 사용은 피하라.

- 주의 : 사용자의 입장에서 생각하라
. 초보자들이 흔히 하는 실수로 함수의 입장에서 이름을 짓는 것이다. 항상 함수를 사용하는 사용자 입장에서 이름을 지어야 한다.  어떻게 해야할지 모르겠다면 왜 이 함수를 만드는지 생각해보자. 적절한 예시가 떠오르지 않는다. 이건 자꾸 연습하다 보면 저절로 될 것이다.

- 주의 : 함수의 내부적인 구현 방법은 생각하지 말고 그 함수의 역할을 생각하라. 함수는 하나의 기능만 가지고 있고 그 기능이 무엇인지에 대해서 이름을 짓는 것이다. 기능을 구현하기 위해 어떤 일을 하건 상관하지 마라. 사과가 몇개인지 알기 위해 사용하는 함수라고 하자. 그럴때 보통 int countApples(); 이런 식의 이름을 지을 것이다. 그러면 사과가 몇개인지만 알면 됐지 이 함수가 재귀호출을 하건 file을 건들건 쓰레드를 만들건 신경쓰지 말라는 말이다.

타입(클레스):
- 클레스 이름은 객체가 아니라 클레스를 묘사해야 한다.(사소하지만 중요한 차이: '사람'이란 클레스 이름대신 '홍길동'이란 클레스 이름을 사용한다면?)

- 상태 값을 가지는 객체를 묘사한다면 명사.

- 함수객체(functor : 함수들 만으로 구성된 객체로 static으로 구현되는 경우가 많다.)거나 가상 call back interface를 구현하는 클레스는 동사 or 잘 알려진 디자인 패턴의 이름

- 클레스가 위의 두가지 성격을 모두 가진다면 이름 정하기가 어렵고, 잘못된 설계일 가능성이 크다.

- DataObject와 같이 당연한 내용을 포함하는 이름은 좋지 않다.(클레스는 data를 포함하는 경우가 많고, 객체화 한다면 당연히 object가 되는 것이 아닌가! 그러니 중복해서 언급할 필요가 없다.) : 좋지 않은 단어 -> class, data, object, type
 

namespace, package:

- 전체적인 내용을 봐라. 이건 꽤 큰 범위라 어휘력에 맡긴다.

- 불필요한 부가적 설명은 피하라 : UI, filesystem, controls등과 같은 이름은 다 좋은 이름들이다. controls_group와 같이 이미 알고있는 내용을 덧붙이지 마라. 길고 쓸데없는 내용은 보기 싫다.

매크로:
= 매크로는 위험하다. (단순 무식 과격하며 힘도 엄청나게 쎄다 : 소스코드가 컴파일 되기 전에 전처리 단계에서 매크로에 해당하는 내용은 모두 지정된 매크로를 거친 값으로 바껴버린다.) 아주 위험하므로 반드시 눈에 띄는 표시가 필요하다.(#define 문을 생각하면 쉽다.)

- 모두 대문자로 표기 (그래야 눈에 잘 띈다)

- 충분히 독특한 이름을 사용해야 한다.(독특한 파일이름이나 프로젝트 이름을 접두사로 붙이는 것이 도움이 될수도 있다. 절대 다른 곳에서 실수로 같은 이름이나 그 이름이 포함된 이름을 사용하면 안된다.)

파일:
- 대소문자에 주의하라. 파일검색은 대소문자 구분을 무시하지만 대소문자를 구분해서 사용하는 곳이 분명히 있다. 책에서는 파일이름을 모두 소문자로 하는 것도 좋은 방법이라고 소개하고 있지만 JAVA에서는 클레스와 인터페이스 이름에 PropreCase를 사용하며 이 이름과 파일 이름이 같아야 제대로 작동한다.

- 헤더파일과 헤퍼의 내용을 구현한 파일의 이름은 같도록 해라. stack.hstack.cpp와 같이 쌍을 이루란 말이다.

- 여러 언어를 혼용해서 사용할 경우 같은 이름에 확장자가 다른 것은 같은 디렉토리에 두지 마라. stack.c, stack.cpp, stack.java가 한 디렉토리에 들어있다면 stack.o파일은 뭘 나타내는 것일까? 자식은 하난데 아빠가 셋이다. 가정에 큰일이 날 수도 있다.

- 확장자를 신경써라. C++에서는 확장자를 .C  .cc  .cpp  .cxx  .c++등 여러가지가 있으며 특이하게 헤더파일의 확장자가 .h대신 .hpp로 쓰이는 경우도 있단다. 이런 마구잡이로 쓰인 확장자는 꽤 거슬리는데 MS의 노예가 된 우리는 .cpp와 .h로 거의 통일되어 있다.

more..


대문자 사용의 관례

more..


일관성을 유지하라
- 하나의 이름에 다양한 규칙을 적용하는 바보는 없을 것이다. Using_underscores_AndProperCase 이런거나 Another_Case 같은 이름은 사용하면 안된다는 말이다.

- 프로젝트 전체에 일관된 규칙을 적용해야 한다.
다음과 같은 코드는 일관성이 없어 제대로 분석되기 어려울 것을 예감할 수 있다.

more..


콘텍스트 활용
※ 범위(scope)
- 이름의 범위는 global, namespace, class, function(method), loop등 다양하다. 범위에 따라 이름이 조금씩 바뀔 수도 있다는 것을 참고하자. 같은 변수라고 해도 함수내에 사용되느냐 전역이냐에 따라 이름이 다르게 사용되는 예가 가끔 있다.

※ 타입(type)
- 위에서 이미 말했지만 type을 이름에 넣지 말라는 것이 Code Craft란 책의 주장이다. string형식의 변수에 address_string이란 이름을 주어 재언급을 하는 것은 피하자는 것이다. 헝가리언 노테이션은 이런 재언급을 목적으로 하고 있기 때문에 종종 비웃음 산다고 한다.)
그러나
내가 생각하기에 이 책의 저자는 구식 사고방식을 가지고 있는 것 같다. JAVA나 C#등과 같이 다양한 콤포넌트들이 구현되어 있고 그것들을 따와서 사용하는 방식의 프로그래밍은 객체의 형식을 모두 기억하기 어렵다.
윈도우 응용 프로그램을 예로 든다면 form하나에 들어가는 구성요소(label, textbox, button등)의 종류가 많으면 이것들을 다 기억하기 어려울 수가 있다. 대체로 이러한 구성요소들은 form이 생성될 때 같이 생성되어서 form이 사라질 때까지 운명을 함께하기 때문에 scope가 너무 크다. 함수 내에서 사용되는 변수들은 type을 사용하는 것이 오히려 거추장스럽지만 범위가 넓은 경우 이름에 포함시켜 주는 것이 맞는 것 같다.(필요하니까 주장하는 사람들이 있는거다.) 다만 어떤 경우에 type을 적어주고 어떤 경우에 뺄 것인지 명확하게 구분지어 놔야 한다.
scope가 작은 경우 빼는 것이 좋고, 넓은 경우 넣는 것이 좋지만 프로젝트 전체에서 형식을 통일시켜야 일관성이 유지되니 심각하게 고민해봐야 할 사항이다.

(나의 경우엔 type을 적지 않는 편이다. 요즘은 tool들이 좋아서 이름만 있으면 어떤 형식인지 다 알려주기 때문에 그닥 필요하지가 않다. tool에 지배당하고 있는건가?)
posted by bluelimn 2008.04.07 20:54

예전에 선배가 시집을 선물해준 적이 있었다. 'love adagio'란 책으로 시인의 이름이 '박상순'이었는데 한동안 그분이 여성작가인줄 알았다. 이름으로 인한 오해는 확실히 알아보기 전에는 계속 작용하기 때문에 그만큼 위험하다. 이름을 잘 붙이는 것은 코딩할 때 상당히 까다롭고 중요한 일이다. 내가 이 카테고리를 만들고 책을 사서 정리하는 이유가 사실은 작명 때문이다.

이름은 다음 3가지를 나타낸다.
identity(신원) : 무엇인지 나타내는 기본적인 것으로 주로 변수(혹은 속성)
begavior(행동) : 무엇을 하는 것인지 나타내는 것으로 주로 함수(혹은 메쏘드)
recognition(인지) : 추상적인 것을 표현함(사상, 우주등 실체를 확인하기 힘든 것들)
이름만 잘 지어도 특별한 주석이나 추가 설명문 없이도 이해하기 쉬운 코드가 된다.

잘못 지어진 이름은 자칫 커다란 위험이 될 수도 있다. 책에는 이런 예를 들었다
void checkForContinue(bool weShouldContinue)
{
      if (weShouldContinue) abort();
}

argument로 넘어오는 weShouldContinue은 이름만 봐도 계속 진행할 필요가 있으면 true, 정지해야 하면 false가 들어오는 것을 예상할 수 있다. 그런데 if문에서 만약 true면 중단하라고 하고있다. 정말이지 어이가 희박한 상황이다.
그렇다면 잘못 지어진 이름 말고 대강 아무런 생각 없이 지어진 이름은 어떨까?

void fun(bool a)
{
     if( a ) b();
}
난 이 함수가 의도하는 것을 도무지 이해할 수가 없다. 처음 언어를 배우는 사람들이 실습용 코드를 작성할 때 변수명을 x,y,z,a,b,c.. 이런 식으로 이어가는 경우가 있다. 이렇게 이름을 짓는다면 무슨 기능을 하는지 하나하나 다 설명해줘야 한다. 설명이야 귀찮지만 하면 된다. 그러나 작성하는 프로그래머조자 코드를 작성하는 도중에 헷갈린다. (인간인 주제에 헷갈리지 않을 것이라고 장담하지 마라.)

* 이름을 붙이는 대상
 - 변수(속성, attribute)
 - 함수(메쏘드, method)
 - 타입: class, enum, struct, typedef
 - C++의 namespace, JAVA의 package
 - 매크로
 - source file(파일명)

기본원칙

묘사적인 이름 :
무엇을 나타내는지 정확해야 한다.

적법한 이름 :
이름도중 공백불가, 대소문자구분 허용, 특수문자불가, (언어에 따라 길이와 사용하는 문자셋(unicode,ascii등)의 차이가 있을 수 있다), 예약서 사용불가. C언어에서는 코드 중간에 선언불가, C/C++에서는 global식별자는 str로 시작하고 다음에 소문자나 밑줄불가하며, std namespace에 속하는 이름도 사용불가.

관용구 사용 :
많은 사람들의 코드를 보고 일반적으로 사용하는 이름이 무엇인지 알면 그걸 지어라. 많이 사용하는 이름 일수록 더 알아보기 쉽다.

정확한 이름 : 사전에 없는 단어를 사용하지 마라. 영어 사용에 약한 한국과 일본에서 간혹 영어대신 자국어를 발음나는대로 적어서 사용하는 경우가 있다. 주문을 나타내는 order대신 jumoon이나 joomoon, jumun(주문)이라고 적어버리는 경우가 있다는 말이다.(허접한 인터넷 사이트에서 간혹 보인다.) 심지어 위의 보기에서 jumoon과 joomoon을 같이 사용하면 다른 기능을 표현하는 경우도 있다.(미친 짓이다.) 사전에 없는 단어를 새롭게 만들어내면 나중에 본인도 무엇을 나타내는지 알아보지 못하는 수가 있다. 뭔지 몰라서 사전을 찾아도 소용 없다.

적절한 길이 : 프로그래머는 단어를 짧게 줄이고 싶어하는 충동을 가지고 있다. 하지만 그렇다고해서 함부로 줄이면 큰일난다. 가능하면 모든 이름에 있어 사전을 따라는 것이 좋다.
단, 줄일 때는 몇가지 규칙이 있다.
 - 반복문의 카운터 : 보통 i,j등으로 사용한다. 이것도 짧은 반복문일 경우에 적당하다.
 - 짧은 범위 : 짧은 범위에서는 지나치게 긴 이름대신 짧은 이름을 사용하고 주석을 달아주면 더 이해하기 쉬울수도 있다.

처음부터 잘 지어라 : 나중에 고치지 뭐..같은 건 없다. 임시로 급하게 작성하는 코드라 해도 생각보다 오래가는 경우가 많다. 나중에 창피당하지 말고 첨부터 잘해라.

-다음번엔 대상별로 이름 붙이는 방법을 알아보도록 하자...