Rest Api 만들기 위해 정리 했던 것이다.


워드로 작성했던거 복사붙여넣기 함.



STANDARD SUECCSS

200 (“OK”)

일반적인 요청 성공을 나타내는 데 사용해야 한다.

200은 클라이언트가 요청한 어떤 액션이었뜬지 REST API가 성공적으로 수행했음을 나타내는 코드로, 클라이언트는 이 코드를 받길 원한다. 또한 더 이상의 할당된 ‘2xx’ 계열의 응답코드가 없다는 뜻이기도 하다. 204 상태 코드와는 달리 200코드는 응답 바디가 포함된다.

 

 

 

201(‘Created’)

성공적으로 리소스를 생성했을 때 사용한다.

새로운 리소스를 이용하여 컬렉션에 생성했거나 스토어에 추가했을 때 201 상태 코드로 응답한다. 컨트롤러의 행동으로 새로운 리소스가 생겨났을 경우에도 201 상태 코드로 응답한다. POST 시 거의 대부분 201 코드가 사용된다고 생각하면 된다.

 

 

 

202(“Accepted”)

비동기 처리가 성공적으로 시작되었음을 알릴 때 사용해야 한다.

202 응답은 클라이언트의 요청이 비동기적으로 처리될 것임을 나타낸다. 이 응답상태 코드는 유효한 요청이었지만, 최종적으로 처리되기 까지는 문제가 생길 수도 있다는 것을 클라이언트에게 알려준다. 보툥 202 응답은 처리 시간이 오래 걸리는 액션에 사용된다.

 

 

204(“No Content”)

응답 바디에 의도적으로 아무것도 포함하지 않을 때 사용한다.

204 상태 코드는 보통 PUT, POST, DELETE 요청에 대한 응답으로 이용하는데, REST API가 응답 메시지의 바디에 어떠한 상태 메시지나 표현을 포함해서 보내지 않을 때 사용한다. APIGET 요청에 204로 응답할 수 있는데, 요청된 리소스는 존재하나 바디에 포함시킬 어떠한 상태 표현도 가지고 있지 않다는 것을 나타낸다.

 

 

 

 

 

 

STANDARD ERROR RESPONSES

오류 응답시에는 응답 바디를 포함한다.

ERROR RESPONSE BODY

에러 시 형태

{

 "error": {

  "errors": [

   {

    "domain": "global",

    "reason": "notFound",

    "message": "Not Found"

   }

  ],

  "code": 404,

  "message": "Not Found"

 }

}

 

 

ERRORS

 

301 (“Moved Permanently”)

 리소스를 이동시켰을 때 사용한다. REST API 리소스 모델이 상당 부분 재설계되었거나 계속 사용할 새로운 URI를 클라이언트가 요청한 리소스에 할당하였다는 것을 나타낸다. REST API는 응답의 Location 헤더에 새로운 URI를 기술해야 한다.

Error Code

Description

movedPermanently

리소스를 이동시켰을 때 사용한다. REST API 리소스 모델이 상당 부분 재설계되었거나 계속 사용할 새로운 URI를 클라이언트가 요청한 리소스에 할당하였다는 것을 나타낸다. REST API는 응답의 Location 헤더에 새로운 URI를 기술해야 한다.

 

 

303 (“See Other”)

다른 URI를 참조하라고 알려줄 때 사용한다. 303응답은 처리가 끝난 컨트롤러 리소스가 잠재적으로 원하지 않는 응답 바디를 보내는 대신, 응답 리소스의 URI를 보냈음을 나타낸다. 이것은 임시 상태 메시지의 URI일 수도 있고, 이미 존재하는 영구적인 리소스의 URI일 수도 있다.

303 상태 코드는 일반적으로 REST API가 클라이언트에 상태 다운로드를 강요하지 않으면서 참조 리소스를 보내는 것을 허용한다. 대신 클라이언트는 응답 Location 헤더에 있는 값으로 GET 요청을 보낼 수 있다.

Error Code

Description

seeOther          

요청은 성공적으로 처리되었다. 응답을 얻기 위해서는 Location 헤더에 지정된 URLGET 요청을 보내라.

mediaDownloadRedirect

요청은 성공적으로 처리되었다. 응답을 얻기 위해서는 Location 헤더에 지정된 URLGET 요청을 보내라.

 

 

304 (“Not Modified”)

대역폭을 절약할 때 사용한다.

이 상태 코드는 응답 바디에 아무것도 없어야 한다는 측면에서 204 (“No Content”)와 유사하다. 주요 차이점은 204는 바디에 보낼 내용이 없을 때 사용하는 반면, 304는 리소스에 대한 상태 정보가 있긴 하지만 클라이언트에 이미 해당 상태의 최신 버전이 있다는 걸 의미할 때 사용한다.

Error Code

Description

notModified       

If-None-Match 헤더에 설정된 조건이 충족 되지 않았다.

If-None-Match 의 값과 서버의 값이 달라야 요청에 대한 데이터를 보내준다.

304 응답 발생시 클라이언트는 자신의 캐시에 있는 데이터를 그냥 사용하면 된다.

 

 

307 (“Temporary Redirect”)

클라이언트가 다른 URI로 요청을 다시 보내게 할 때 사용해야 한다. 307 응답은 REST API 가 클라이언트의 요청을 처리하지 않을 것임을 나타낸다. 클라이언트는 응답 메시지의 Location 헤더에 지정된 URI로 요청을 다시 보내야한다.

Error Code

Description

temporaryRedirect

요청을 Location 헤더에 지정된 URL로 다시 보내라.

 

 

400 (“Bad Request”)

일반적인 요청 실패에 사용해야 한다. 기본적으로 다른 4xx 응답들과 매칭되는게 없는 REST API 고유의 에러 정보를 응답 바디에 포함하여 더 자세하게 에러 정보를 표시할 수 있다.

Error Code

Description

                     

 

 

 

 

 

 

 

 

401 (“Unauthorized”)

클라이언트 인증에 문제가 있을 때 사용해야 한다.

401 오류 응답은 클라이언트가 적절한 인증 없이 보호된 리소스를 사용하려고 할 때 발생한다. 인증을 잘못하거나 아예 인증하지 못할 경우 발생한다.

Error Code

Description

unauthorized      

해당 사용자는 해당 요청에 대한 인증된 사용자가 아니다.

authError

요청에 제공된 인증 자격 증명이 유효하지 않습니다. 인증 HTTP 요청 헤더의 값을 확인하십시오.

expired

세션이 만료되었다. Authorization HTTP 요청 헤더 값을 확인하라.

lockedDomainExpired

이전에 유효한 고정 도메인이 만료 되었기 때문에 요청이 실패했다.

required

사용자는 이 API 요청을 하려면 로그인을 해야한다. 인증 HTTP 요청 헤더 값을 확인해라.

 

 

 

402 (“PAYMENT_REQUIRED”)

요금에 대한 오류 반환이다.

Error Code

Description

dailyLimitExceeded402

일일 사용 요금 한도를 초과했다.

quotaExceeded402

요청한 작업 할당량이 허용하는 것보다 더 많은 자원을 필요로한다. 즉 금액이 모자란다.

user402

요청한 작업은 인증된 사용자의 지불 방식을 필요로한다.

 

 

 

 

403 (“Forbidden”)

인증 상태에 상관없이 액세스를 금지할 때 사용해야 한다.

403 오류 응답은 클라이언트의 요청은 정상이지만, REST API가 요청에 응하지 않는 경우를 나타낸다403 응답은 인증에 문제가 있어서가 아니다. 만약 인증에 문제가 있다면 401를 사용해라. REST API에서 어플리케이션 수준의 접근 권한을 적용하고자 할 때 403을 사용한다. 예를 들어 클라이언트는 REST API 리소스의 전체가 아니라 일부에 대한 접근만 허가된 경우가 있다. 클라이언트가 허용된 범위 외의 리소스에 접근하려고 할 때 REST API403으로 응답해야 한다.

Error Code

Description

forbidden

요청이 금지되어 완료되지 못했다.

accessNotConfigured

해당 프로젝트가 이 API 호출에 접근권한이 없다.

accessNotConfigured

해당 프로젝트가 블록당했다.

accountDeleted

요청에 대한 인증 자격 증명과 관련된 사용자 계정이 삭제되었다.

accountDisabled

요청에 대한 인증 자격증명과 관련된 사용자 계정이 사용불가상태이다.

accountUnverified

요청을 하는 사용자의 이메일 혹은 id가 확인 되지 않았다. 혹은 인증이 확인되지 않았다.

concurrentLimitExceeded

동시 사용 한계 때문에 금지 되었다.

dailyLimitExceeded

API의 일일 할당량 제한에 도달했다.

dailyLimitExceeded

일일 할당량 제한에 도달 하고 있으며 이 사용자는 차단되었다.

dailyLimitExceededUnreg

인증되지 않은 API 사용을 위한 일일 한도를 초과했기 때문에 실패했다.

downloadServiceForbidden

API는 다운로드를 지원하지 않는다.

insufficientAudience

요청 이 시청자에 대해 완료 될 수 없다.

insufficientAuthorizedParty

요청은 어플리케이션에 대해 완료 할 수 없다.

insufficientPermissions

인증된 사용자이지만 이 요청을 실행 할 수 있는 권한은 없다.

limitExceeded

요청은 액세스 또는 속도 제한으로 인해 완료되지 않을 수 있다.

lockedDomainForbidden

API는 락된 도메인을 지원하지 않는다.

quotaExceeded

요청한 작업 할당량이 허용하는 것보다 더 많은 자원을 필요로 한다.

rateLimitExceeded

너무 많은 요청을 주어진 범위내에서 보냈다.

rateLimitExceededUnreg

속도 제한이 초과되었다. API 호출을 계속 할 수 있도록 조치를 취해야한다.

responseTooLarge

요청된 리소스가 반환하기에 너무 크다.

servingLimitExceeded

API 에 지정된 전체 속도 제한은 이미 도달했다.

sslRequired

해당 작업은 SSL을 써야한다.

unknownAuth

API 서버는 요청에 사용되는 인증 방식을 인식하지 못한다. Authorization HTTP 요청헤더를 확인해라.

userRateLimitExceeded

사용자 별 속도 제한에 도달했기 때문에 요청이 실패

userRateLimitExceededUnreg

사용자 별 속도 제한에 도달했고 이 클라이언트는 식별되지 않았다.

variableTermExpiredDailyExceeded

변수가 만료되었고 일일 한계량을 초과했다.

variableTermLimitExceeded

변수의 할당 제한에 도달했기 때문에 요청이 실패했다.

 

 

404 (“Not Found”)

요청 URI에 해당하는 리소스가 없을 때 사용한다.

404 오류 상태 코드는 말그대로 클라이언트가 요청한 URI에 해당하는 리소스가 존재하지 않을 때 사용한다.

Error Code

Description

notFound

요청과 관련된 리소스가 존재하지 않는다.

notFound

요청과 관련된 리소스를 찾을 수 없다.

unsupportedProtocol

요청에 사용된 프로토콜은 지원하지 않는다.

 

 

405 (“Method Not Allowed”)

HTTP 메서드가 지원되지 않을 때 사용해야 한다.

클라이언트가 허용되지 않는 HTTP 메서드를 사용하려 할 때, API405 오류 응답을 한다. 읽기 전용 리소스는 GET 메소드와 HEAD 메서드만 지원하며, 컨트롤러 리소스는 PUT 메서드와 DELETE메서드를 제외한 GET 메서드와 POST 메서드만 허용할 것이다.

405 응답에는 Allow 헤더가 포함되어야 하며, 그 값으로 리소스가 지원하는 HTTP 메서드를 다음 예와 같이 나타내야 한다.

Allow : GET, POST

 

Error Code

Description

httpMethodNotAllowed

이 리소스에 대한 HTTP 메소드는 지원하지 않는다.

 

 

406 (“Not Acceptable”)

요청된 리소스 미디어 타입을 제공하지 못 할 때 사용해야 한다.

406 오류 응답은 클라이언트의 Accept 요청 헤더에 있는 미디어 타입중 해당하는 것을 만들지 못할 때 발생한다. 예를 들어, APIjson(application/json) 데이터 포맷만 지원한다면 xml(application/xml) 포맷 데이터를 요청한 클라이언트는 406 응답을 받는다.

Error Code

Description

notAcceptable

해당 미디어 타입은 제공하지 않는다.

 

 

409 (“Conflict”)

리소스 상태에 위반되는 행위를 했을 때 사용해야 한다.

409 오류 응답은 클라이언트 요청에 의해 REST API 리소스가 불가능 또는 모순 상태가 될 수 있는 경우에 사용한다. 예를 들어 클라이언트가 비어 있지 않은 리소스를 삭제하라고 요청하면, REST API에서 이 응답 오류를 보낸다.

Error Code

Description

conflict

요청된 작업이 기존 항목과 충돌하기 때문에 API 요청을 완료 할 수 없다. 중복 항목에 대한 오류는 일반적인 상황보다 좀더 구체적으로 표현한다.

duplicate

이미 존재하는 리소스를 생성하라고 했을 때 발생한다.

 

 

 

410 (“Gone”)

존재 하지 않는 리소스에 대한 삭제 요청 시 사용해야 한다.

Error Code

Description

deleted

삭제 요청한 리소스가 이미 존재 하지 않는다.

 

 

412 (“Precondition Failed”)

조건부 연산을 지원할 때 사용한다.

412 오류 응답은 특정한 조건이 만족될 때만 요청이 수행되도록 REST API로 알려준다. 클라이언트가 요청 헤더에 하나 이상의 전제 조건(If-Match , If-None_match )을 지정할 경우 발생하며, 이러한 조건이 만족되지 않으면 412응답은 요청을 수행하는 대신에 이 상태 코드를 보낸다.

Error Code

Description

conditionNotMet

요청에 If-Match If-None-Match HTTP 헤더의 조건이 충족되지 않았다.

 

 

 

413 (“Request_entity_too_large”)

413 오류 응답은 요청의 크기가 너무 클 때 사용한다.

Error Code

Description

backendRequestTooLarge

요청이 너무 크다.

batchSizeTooLarge

요청에 너무 많은 요소가 포함되어 있다.

uploadTooLarge

요청에 포함된 데이터의 크기가 너무 커서 요청이 실패했다.

 

 

 

415 (“Unsupported Media Type”)

요청의 페이로드에 있는 미디어 타입이 처리되지 못했을 때 사용해야 한다.

415 오류 응답은 요청 헤더의 Content-Type에 기술한 클라이언트가 제공한 미디어 타입을 처리하지 못할 때 발생한다. 예를 들어 API json(application/json)으로 포맷된 데이터만 처리할 수 있을 때, 클라이언트가 xml(application/xml)로 포맷된 데이터로 요청하면 415응답을 받는다.

 

Error Code

Description

unsupportedMediaType

요청에 포함된 미디어 타입을 처리하지 못한다.

 

 

416 (“Requested Range Not Satisfiable”)

요청이 만족될 수 없는 범위를 지정할 때 사용한다.

Error Code

Description

requestedRangeNotSatisfiable

요청이 만족될 수 없는 범위를 지정할 때 사용한다.

 

 

 

417 (“Expectation Failed”)

클라이언트의 기대가 서버에 의해 만족 될 수 없을 때 사용한다.

Error Code

Description

expectationFailed

클라이언트의 기대가 서버에 의해 만족 될 수 없다.

 

 

 

428 (“Precondition Required”)

해당 요청이 전제 조건이 꼭 필요 할 때 사용한다. 이 요청이 성공하려면 If-MatchIf-None-Match 헤더가 요청에 포함되어야 한다.

Error Code

Description

preconditionRequired

해당 요청이 전제 조건이 꼭 필요 할 때 사용한다. 이 요청이 성공하려면 If-Match If-None-Match 헤더가 요청에 포함되어야 한다.

 

 

 

429 (“Too Many Requests”)

너무 많은 요청이 같은 시간에 발생 했을 경우 사용한다.

Error Code

Description

rateLimitExceeded

너무 많은 요청이 주어진 시간 범위 내에서 보냈다.

 

 

 

500 (“Internal Server Error”)

API가 잘못 작동할 때 사용해야 한다.

500 오류 응답은 일반적인 REST API오류 응답이다. 웹 프레임워크는 대부분 예외 사항을 발생시키는 요청 핸들러 코드가 실행 될 경우 자동적으로 이 응답 코드를 발생시킨다. 500 오류는 클라이언트의 잘못으로 발생한 것이 아니기 때문에 클라이언트가 이 응답을 발생시킨 것과 동일한 요청을 다시 시도하면 다른 응답을 받을 수도 있다.

Error Code

Description

internalError

요청이 내부 오류로 인해 실패했다.

 

 

 

501 (“Not Implemented”)

REST API 가 아직 구현되지 않았을 때 이 응답을 사용한다. 설계에서부터 없던 API가 아닌 지원할 것이지만 아직 구현하지 않았을 때 사용한다.

Error Code

Description

notImplemented

해당 요청에 대한 명령은 아직 구현하지 않았다.

unsupportedMethod

요청이 알려지지 않은 메소드나 명령을 실행하려 했기 때문에 실패했다.

 

 

 

503 (“Service Unavailable”)

RESTFUL 서버가 점검중이거나 장애발생시 서비스에 연결 되지 않을 때 사용한다.

Error Code

Description

backendError

백엔드 오류가 발생했다.

backendNotConnected

요청이 연결오류로 실패했다.

notReady

API 서버가 아직 준비되지 않았다.

 



Rest api 만들며 보기 편하게 정리 했던 것.

실제로 사용하는 것은 몇개 없네요. 


CODE

Description

1XX 조건부 응답

 

100 (계속)

요청자는 요청을 계속해야한다. 서버는 이 코드를 제공하여 요청의 첫 번째 부분을 받았으며 나머지를 기다리고 있음을 나타낸다.

101 (프로토콜 전화)

요청자가 서버에 프로토콜 전환을 요청했으며 서버는 이를 승인하는 중이다.

 

 

2XX 성공

 

200 (성공)

서버가 요청을 제대로 처리했다는 뜻이다. 이는 주로 서버가 요청한 페이지를 제공했다는 의미로 쓰인다.

201 (작성됨)

성공적으로 요청되었으며 서버가 새 리소스를 작성했다.

202 (허용됨)

서버가 요청을 접수했지만 아직 처리하지 않았다.

203 (신뢰할 수 없는 정보)

서버가 요청을 성공적으로 처리했지만 다른 소스에서 수신된 정보를 제공하고 있다.

204 (컨텐츠 없음)

서버가 요청을 성공적으로 처리했지만 컨텐츠를 제공하지 않는다.

205 (컨텐츠 재설정)

서버가 요청을 성공적으로 처리했지만 컨텐츠를 표시하지 않는다. 204응답과 달리 이 응답은 용청자가 문서보기를 재설정할 것을 요구한다. ( : 새 입력을 위한 양식 비우기)

206 (일부 컨텐츠)

서버가 GET 요청의 일부만 성공적으로 처리했다.

207 (다중 상태)

 

208 (이미 보고됨)

 

226 IM Used

 

 

 

3XX 리다이렉션 완료

클라이턴트 요청을 마치기 위해 추가 동작을 취해야 한다.

300 (여러 선택항목)

서버가 요청에 따라 여러 조치를 선택할 수 있다. 서버가 사용자 에이전트에 따라 수행할 작업을 선택하거나, 요청자가 선택할 수 있는 작업 목록을 제공한다.

301 (영구 이동)

요청한 페이지를 새 위치로 영구적으로 이동했다. GET 또는 HAED 요청에 대한 응답으로 이 응답을 표시하면 요청자가 자동으로 새 위치로 전달된다.

302 (임시 이동)

현재 서버가 다른 위치의 페이지로 요청에 응답하고 있지만 요청자는 향후 요청 시 원래 위치를 계속 사용해야 한다.

303 (기타 위치 보기)

요청자가 다른 위치에 별도의 GET 요청을 하여 응답을 검색할 경우 서버는 이 코드를 표시한다. HAED 요청 이외의 모든 요청을 다른 위치로 자동으로 전달한다.

304 (수정되지 않음)

마지막 요청 이후 요청한 페이지는 수정되지 않았다. 서버가 이 응답을 표시하면 페이지의 컨텐츠를 표시하지 않는다. 요청자가 마지막으로 페이지를 요청한 후 페이지가 변경되지 않으면 이 응답(if-Moified-Since HTTP 헤더라고함)을 표시 하도록 서버를 구성해야 한다.

305 (프록시 사용)

요청자는 프록시를 사용하여 요청한 페이지만 액세스할 수 있다. 서버가 이 응답을 표시하면 요청자가 사용할 프록시를 가리키는 것이기도 하다.

307 (임시 리다이렉션)

현재 서버가 다른 위치의 페이지로 요청에 응답하고 있지만 요청자는 향후 요청 시 원래 위치를 계속 사용해야 한다.

308 (영구 리다이렉션)

 

 

 

4XX 요청 오류

 

400 (잘못된 요청)

서버가 요청의 구문을 인식하지 못했다.

401 (권한 없음)

이 요청은 인증이 필요하다. 서버는 로그인이 필요한 페이지에 대해 이 요청을 제공할 수 있다.

403 (금지됨)

서버가 요청을 거부하고 있다.

404 (찾을 수 없음)

서버가 요청한 페이지를 찾을 수 없다. 예를 들어 서버에 존재하지 않는 페이지에 대한 요청이 있을 경우 서버는 이 코드를 제공한다.

405 (허용되지 않는 방법)

요청에 지정된 방법을 사용할 수 없다.

406 (허용되지 않음)

요청한 페이지가 요청한 컨텐츠 특성으로 응답할 수 없다.

407 (프록시 인증 필요)

이 상태 코드는 401(권한 없음)과 비슷하지만 요청자가 프록시를 사용하여 인증해야한다. 서버가 이 응답을 표시하면 요청자가 사용할 프록시를 가리키는 것이기도 한다.

408 (요청 시간초과)

서버의 요청 대기가 시간을 초과하였다.

409 (충돌)

서버가 요청을 수행하는 중에 충돌이 발생했다. 서버는 응답할 때 총돌에 대한 정보를 포함해야 한다. 서버는 PUT 요청과 충돌하는 PUT 요청에 대한 응답으로 이 코드를 요청 간 차이점 목록과 함께 표시해야 한다.

410 (사라짐)

서버는 요청한 리소스가 영구적으로 삭제되었을 때 이 응답을 표시한다. 404(찾을 수 없음) 코드와 비슷하며 이전에 있었찌만 더 이상 존재하지 않는 리소스에 대해 404 대신 사용하기도 한다. 리소스가 영구적으로 이동된 경우 301을 사용하여 리소르의 새 위치를 지정해야 한다.

411 (길이 필요)

서버는 유효한 컨텐츠 길이 헤더 입력란 없이는 요청을 수락하지 않는다.

412 (사전조건 실패)

서버가 요청자가 요청 시 부과한 사전조건을 만족하지 않는다.

413 (요청 속성이 너무 큼)

요청이 너무 커서 서버가 처리할 수 없다.

414 (요청 URI가 너무 김)

요청 URI(일반적으로 URL)가 너무 길어 서버가 처리할 수 없다.

415 (지원되지 않는 미디어 유형)

요청이 요청한 페이지에서 지원하지 않는 형식으로 되어 있다.

416 (처리할 수 없는 요청범위)

요청이 페이지에서 처리할 수 없는 범위에 해당된느 경우 서버는 이 상태 코드를 표시한다.

417 (예상 실패)

서버는 Expect 요청 헤더 입력란의 요구사항을 만족할 수없다.

418 (I’m a teapot)

 

420 (Enhance Your Calm)

 

422 (처리할 수 없는 엔티티, WebDAV)

 

423 (잠김, WebDAV)

 

424 (실패된 의존성)

 

425 (정렬되지 않은 컬렉션, 인터넷 초안)

 

426 (업그레이드 전용)

 

428 (전제조건 필요)

 

429 (너무 많은 요청)

 

431 (요청 헤더 필드가 너무 큼)

 

444 (응답 없음)

 

449 (다시 시도, 마이크로소프트)

 

450 (윈도 자녀 보호에 의해 차단됨, 마이크로소프트)

 

451 (법적인 이유로 이용 불가)

 

494 (요청 헤더가 너무 큼)

 

495 (Cert 오류)

 

496 (Cert 없음)

 

497 (HTTP to HTTPS)

 

499 (클라이언트가 요청을 닫음)

 




http://www.boannews.com/ - 보안뉴스

http://www.zdnet.co.kr/ - 지디넷 코리아

http://www.newstomato.com/ - 토마토뉴스

http://www.ddaily.co.kr/ - 디지털데일리

http://www.ciokorea.com/ - CIO

http://www.itworld.co.kr/ - ITWORLD

http://www.etnews.com/ - ETNEWS

http://www.netmanias.com/  - NETMANIAS (기술적인 내용이 존재)

http://www.itdaily.kr/ - IT 한국의 새로운 창

간혹 백엔드" ` " 를 써서 쉘 스크립트를 작성해야 될 때가 있다.

백엔드를 썼는데 그 백엔드 내부에 또 백엔드를 써야될 때

억지로 예문을 만들어 보았다.

예) $ ls -al `ls `pwd` `

위와 같이 내부에 백엔드가 존재할 때 이렇게 하자

$ ls -al `ls \`pwd\``

쉘 명령어에서 \ 은 이스케이프 문자로 이스케이프 문자 다음에 백엔드는 문자 그대로 해석된다. 

해석단계

ls -al `ls \`pwd\``  =>  `ls \`pwd\`` => ls `pwd` => pwd

나의 글재주가 부족하여 모라 말로는 설명을 못하겠다.

외부의 백엔드가 해석되면서 \` 은 일반 문자 ` 로 해석되고 `은 다시 백엔드로 해석되는 것이다..


정리 

이중 중첩의 경우 = ` \`  \`  `

삼중 중첩의 경우 = ` \`  \\\`  \\\`  \` `


내 글 재주가 모자라 이해하는 사람이 있을까마는...

누군가는 내 글을 이해했으면 좋겠다..ㅜㅜ

int 보다 작은 데이터 형은 연산전에 int (정수) 형으로 캐스팅 된다.

암시적인 타입 캐스팅후 문제점이 아래에 있다. 너무나도 쉽게 넘어갈수 있는 문제지만 그 결과는 참담하다.
이제부터는 모든 연산에 대해서 타입 캐스팅을 확실히 해야겠다.

또한 왠만하면 연산을 한 라인에 쓰기 보다는 여러 라인으로 한 연산씩 처리해야겠다.
맨 아래의 해결 방법도 좋지만 이 방법도 사용해볼만 하다.

uint8_t port = 0x5a;
uint8_t temp = (~port);
uint8_t result_8 = temp >> 4;




Noncompliant Code Example

This noncompliant code example demonstrates how performing bitwise operations on integer types smaller than int may have unexpected results.

uint8_t port = 0x5a;
uint8_t result_8 = ( ~port ) >> 4;

In this example, a bitwise complement of port is first computed and then shifted 4 bits to the right. If both of these operations are performed on an 8-bit unsigned integer, then result_8 will have the value 0x0a. However, port is first promoted to a signed int, with the following results (on a typical architecture where type int is 32 bits wide):

Expression

Type

Value

Notes

port

uint8_t

0x5a

 

~port

int

0xffffffa5

 

~port >> 4

int

0x0ffffffa

Whether or not value is negative is implementation-defined.

result_8

uint8_t

0xfa

 

Compliant Solution

In this compliant solution, the bitwise complement of port is converted back to 8 bits. Consequently, result_8 is assigned the expected value of 0x0aU.


uint8_t port = 0x5a;
uint8_t result_8 = (uint8_t) (~port) >> 4;

원본 : http://www.cyberciti.biz/faq/how-do-i-find-what-dependencies-a-rpm-file-has/



How do I find what dependencies a rpm file has?

BY  ON JANUARY 14, 2006 · 2 COMMENTS · LAST UPDATED AT AUGUST 28, 2006

RPM is a Package Manager for popular distribution such as Red Hat, Suse and many others. It is a powerful command line package management system for installing uninstalling, verifying, querying, and updating Linux computer software packages.

You can finding out what dependencies a rpm file has ie it will tell you what you need to install package with following command: 
rpm -qpR {.rpm-file} 
rpm -qR {package-name} 

Find out what dependencies a uninstalled rpm file called mediawiki-1.4rc1-4.i586.rpm: 
# rpm -qpR mediawiki-1.4rc1-4.i586.rpm

It will print list of dependencies on screen (output):

  mod_php
 php-session
 php-gettext
 php-zlib
 php-mysql
 ImageMagick-Magick++
 tetex
 cjk-latex
 rpmlib(PayloadFilesHavePrefix) 

However RPM has in build mechanism to tell you about dependencies. Just try to install package and it will give you list of dependencies. 
# rpm -ivh mediawiki-1.4rc1-4.i586.rpm

Output:

  error: Failed dependencies:
    mod_php is needed by mediawiki-1.4rc1-4
    php-session is needed by mediawiki-1.4rc1-4
    php-gettext is needed by mediawiki-1.4rc1-4
    php-zlib is needed by mediawiki-1.4rc1-4
    php-mysql is needed by mediawiki-1.4rc1-4
    ImageMagick-Magick++ is needed by mediawiki-1.4rc1-4
    tetex is needed by mediawiki-1.4rc1-4
    cjk-latex is needed by mediawiki-1.4rc1-4 

Note:

  • .rpm file: File with .RPM extension. Typically this file is not installed. It may be on CD or you just downloaded from Internet.
  • package-name: It is installed RPM file.

You can solve dependencies problem by installing each individual package(s). If you are using Red hat Linux then you can try this tip . If you are using Fedora core Linux then try yum . If you are using Suse linux then use Yast to install rpms.

원본 : http://certifie.com/ca-bundle/


ca-bundle.crt

Information on obtaining or building a ca-bundle.crt file

What is ca-bundle.crt?

ca-bundle.crt is a file that contains well known root CAcertificates.(What is a root CA?)

What is it used for?

It is used by openssl to validate certificates issued by well known root CAs.  It is also used by any third party applications that use openssl, and some that don't.

Why do I need to get ca-bundle.crt here/Why do I need to build it myself?  Why isn't it provided by (insert your tool here) developers?

It was originally produced by Netscape.  However, after version 4.x, Netscape no longer uses the ca-bundle.crt format.  3rd party products (like openssl) still do use it.  Most of the versions of ca-bundle.crt floating around the net are very old.

In any case, you may feel safer building it yourself.  Building it yourself lets you decide what root CAs you want to trust.

Forget about building it myself, where can I get a pre-built copy?

Here's one I buiilt using Mozilla's NSS library v3.7 built-in "Builtin Roots Module" : ca-bundle.crt

SHA1 sum : 0498c8ef0fa22f241cd2bcc4b27b71714f39348c
MD5 sum :   83e2ea55aeb9fc9578554decfb0ec5f6

How do I go about building ca-bundle.crt myself?

First, you'll need a bunch of root CA certificates that you trust :)

I recommend getting Mozilla's list.  Its destributed in their NSS sourcecode.  Here are the steps/code to produce ca-bundle.crt from NSS code :

The following instructions have been tried on Mandrake linux 8.2

  1. Download Mozilla's NSS code : nss 3.7 release notes
  2. Download dumpCerts.java and create_bundle.sh from certifie.com.
  3. build dumpCerts.java
    • use jss33.jar from NSS
    • javac -classpath jss33.jar dumpCerts.java
  4. Install a Mozilla browser.
  5. run dumpCerts.java
    • Set LD_LIBRARY_PATH to the directory where you have put NSS.  it should point to a directory that has nss/lib under it.
    • run : java -classpath .:jss33.jar dumpCerts $HOME/.mozilla/default/<user dir>.slt/   ca-bundle.crt
  6. That's it.

I've got some special CA certs not included by Mozilla that I wan't to add to ca-bundle.crt.  How can I add them?

You can use create_bundle.sh.  It is called by dumpCerts.java to build the ca-bundle.crt file from NSS data.  It may also be run stand-alone and its output appended to ca-bundle.crt.  You may also want to cut and paste its output into ca-bundle.crt to keep it alphabetized properly (if your picky).

What license is your code distributed under?  Can I use it for commercial uses?

You may use the two files  dumpCerts.java and   create_bundle.sh however you'd like, although I make no claims that they will function correctly.  Use them at your own risk.  

The file ca-bundle.crt is provided here under the assumption that it is data/facts and may be used freely by anyone who wishes to use it.

I have some additional questions.  How may I contact you to ask them?

You can contact me at : questions@certifie.com

  1. barato timberland 2012.12.25 12:59

    Des analyses effectuées en mars 2010 révélaient déjà une trace de contamination à la dioxine dans des graisses alimentaires commercialisées par l'entreprise allemande Harles und Jentzch, http://www.timberlandbaratas.com Timberland Online, a rapporté vendredi le journal Hannoversche Allgemeine Zeitung (HAZ). Le ministère régional de l'Agriculture du Schleswig-Holstein (nord), http://www.timberlandbaratas.com outlet timberland, Etat régional où Harles und Jentzsch a son siège, a confirmé jeudi cette confirmation tout en assurant n'avoir été informé que le 27 décembre des résultats de ce test réalisé le 19 mars, http://www.timberlandbaratas.com botas timberland, ajoute le HAZ, http://www.timberlandbaratas.com Hombre Timberland. A l'époque, les taux relevés de dioxine étaient plus de deux fois supérieurs à la norme, précise le journal. Mais l'entreprise n'a pas communiqué au ministère régional les résultats de cette analyse effectuée de sa propre initiative, a affirmé un porte-parole du ministère à Kiel (nord), http://www.timberlandbaratas.com Timberland shops, cité par le Hannoversche Allgemeine Zeitung, http://www.timberlandbaratas.com Timberland. Entreprises Espionnage chez Renault : la piste chinoise Economie Temps de travail: la CGT veut renégocierRelated articles:


    http://www.5osa.com/2766 Environ 4700 exploitations

    http://www.mindgolf.net/23 So research on the internet which of the city's airports are closest to the city center

  2. Un homme a été ma, http://www.moncleroutletespain.com/ http://www.moncleroutletespain.com/?trisé par des passagers mercredi lors d'une tentative de détournement d'un avion effectuant la liaison entre Oslo et Istanbul, http://www.moncleroutletespain.com/ moncler, rapporte la presse turque, http://www.moncleroutletespain.com/ moncler outlet, citant d'autres passagers, http://www.moncleroutletespain.com/ moncler españa.Related articles:


    http://aspworldtour.tistory.com/487 http://aspworldtour.tistory.com/487

    http://aspworldtour.tistory.com/420 http://aspworldtour.tistory.com/420


고가용성 

 l  고가용성

n  IBM Cloud의 고가용성 애플리케이션
http://www.ibm.com/developerworks/kr/cloud/library/cl-highavailabilitycloud/

n  HighAvailabilty
http://www.linux-ha.org/wiki/Main_Page

n  Linux High Availability HOWTO
http://horms.net/projects/redundant_content/related/linux-ha/High-Availability-HOWTO.html

 

l  MYsql 고가용성(mysql , heartbeat, DRBD 를 이용)

n  mysql, heartbeat, DRBD
http://forge.mysql.com/w/images/5/52/FOSDEM-MySQL-HA-2009-02-08.pdf

n  MySQL HA/Scalability Guide
http://downloads.mysql.com/docs/mysql-ha-scalability-en.pdf

n  Multi-Master Replication Manager for MySQL
http://mysql-mmm.org/

n  MySQL High Availability Solutions
http://www.mafiree.com/docs/MySQL_High_Availability_Solutions.pdf

n  고 가용성 high Availabilty 클러스터 시스템 구축
http://syszone.co.kr/PDF/enterprise-linux-4-1.pdf

n  DRBD + Heartbeat + MySQL 활용
http://blog.lovediary.co.kr/tag/drbd+mysql

n  리플리케이션, 클러스터, 클러스터리플리케이션, DRBD 간단 설명
http://www.sqldic.co.kr/replication.action

n  DRBD 설치 및 설정
http://chonnom.com/bbs/board.php?bo_table=B25&wr_id=16&page=2

n  DRBD MySQL HowTO (mysql drbd 연동법)
http://www.clusterlabs.org/wiki/DRBD_MySQL_HowTo

n  DRBD Network Mirroring
http://blog.naver.com/ckwnan?Redirect=Log&logNo=20113317590

n  mysql 5.6 메뉴얼(drbd 관련 mysql 설정등등)
http://dev.mysql.com/doc/refman/5.6/en/ha-drbd.html

mysql master master replication
http://www.linux-faqs.info/mysql/mysql-master-master-replication

n  DRBD
http://www.drbd.org/

n  DRBD 설정 및 실행
http://jook.pe.kr/xe/linux/1927

n  DRBD 를 이용한 고가용성 개념설명
http://www.ibm.com/developerworks/kr/library/l-drbd/index.html



 로드밸런싱
 l  로드밸런싱 종류

1. SLB(Server Load Balancing)

2. FLB(Firewall Load Balancing)

3. GLB(Gateway Load Balancing)

4. CSLB(Cache Load Balancing)

5. VLB(VPN Load Balancing)

6. DLB(DNS Load Balancing)

7. WLB(WebServer Load Balancing)

l   

l  linux 기반의 고가용 로드밸런싱 웹 서비스 구축방안
http://www.scribd.com/doc/72850679/Linux-%EA%B8%B0%EB%B0%98%EC%9D%98-%EA%B3%A0%EA%B0%80%EC%9A%A9-%EB%A1%9C%EB%93%9C%EB%B0%B8%EB%9F%B0%EC%8B%B1-%EC%9B%B9-%EC%84%9C%EB%B9%84%EC%8A%A4-%EA%B5%AC%EC%B6%95%EB%B0%A9%EC%95%88

l  로드밸런싱 리눅스편
http://hakkoo.net/zeroboard/zboard.php?id=study&page=1&sn1=&divpage=1&category=1&sn=off&ss=on&sc=on&select_arrange=hit&desc=desc&no=433&PHPSESSID=76aa41e67c64db308ddebbb1de47fa83



 모니터링
 l  시스템 모니터링 관련 라이브러리 libstatgrab

http://www.i-scream.org/libstatgrab/

l  SNMP
http://www.joinc.co.kr/modules/moniwiki/wiki.php/article/SNMP_%B0%B3%BF%E4

l  Cacti
http://theeye.pe.kr/entry/the-good-nms-tool-is-cacti
http://www.cacti.net (
정식사이트)

l  Top 25 Best Linux Performance Monitoring and Debugging Tools
http://www.thegeekstuff.com/2011/12/linux-performance-monitoring-tools/

l  모니터링 툴에 관한 linuxtoday 링크
Top 25 Best Linux Performance Monitoring and Debugging Tools
http://linuxtoday.com/it_management/2011120800141OSSW
6 More of the Best Free Linux Monitoring Tools
http://linuxtoday.com/it_management/2010112700235OSSVSW
5 Linux Network Monitoring Tools
http://linuxtoday.com/it_management/2010110402035NWSWNT
The Top 12 Native Linux System Monitoring Tools
http://linuxtoday.com/it_management/2010042901835OSBZSV
Smart Power Monitoring with Network UPS Tools
http://linuxtoday.com/it_management/2009111303235OSHWNT
9 of the Best Free Linux System Monitoring Tools
http://linuxtoday.com/it_management/2009071300235RVSWNT

l  리눅스 시스템 모니터링 시스템 최적화
http://www.hanguk.jp/doc/systemMonitoring_basic.pdf



장애/로그 등 알림 서비스 
       l  SMS 전송 API 제공(유료) 기업

http://api.allat.co.kr/sopen/index/index.jsp

l  smtp 분석자료
http://secretofsh.tistory.com/attachment/cfile25.uf@1308900B4A63F33506CAEE.doc

l  SMTP 프로톸콜의 이해 1,2,3
http://www.okjsp.pe.kr/bbs?act=DOWN&maskname=10191873562294&fileName=st1_SMTP.hwp
http://www.okjsp.pe.kr/bbs?act=DOWN&maskname=10191873562053&fileName=st2_Mail.hwp
http://www.okjsp.pe.kr/bbs?act=DOWN&maskname=10191873561312&fileName=st3_Mail.hwp

l  MailMan 라이브러리
http://www.chilkatsoft.com/refdoc/c_CkMailManRef.html

원격통합로그서버 (rsyslog + loganalyzer)
http://chonnom.com/bbs/board.php?bo_table=B19&wr_id=347 - 구축법



 온라인 패치/업데이트

 l  패치

n  패치란?
패치는 프로그램의 일부를 빠르게 고치는 일을 말한다.(patch 란 용어 대신 fix 란 말을 쓰는 경우도 있다.) 소프트웨어 제작자의 베타판이나 시험기간중 또는 제품이 정식으로 발매된 이후에도 문제는 반드시 발견된다. 패치는 사용자에게 제공되는 즉각적인 해결책으로서, 소프트웨어 메이커의 웹사이트 등으로부터 다운로드 받을 수 있다. 그러나, 패치는 그 문제를 위해 반드시 최상의 해결 방안은 아니며, 소프트웨어 개발자들은 종종 더 나은 해결책을 찾아내어 다음에 출시 될 정식 버젼의 패키지 프로그램에 반영하곤 한다.
패치는 코통 컴파일된 코드, 즉 바이너리 코드 또는 목적 코드를 대체하거나 추가로 삽입하는 목적으로 개발되고 배포된다. 대형 운영체계에서는 패치의 설치 내용을 기록, 추적하고, 관리하는 특별한 프로그램이 제공되기도 한다.

n  대규모 네트워크를 지원하는 계층적 패치 관리시스템 설계 및 구현
http://img.kisti.re.kr/originalView/originalView.jsp?url=/soc_img/society//kias/SOBTA9/2004/y2004m05a/SOBTA9_2004_y2004m05a_199.pdf

n  휴대 정보터미널을 위한 애플리케이션 자동 설치 시스템의 설계 및 구현
http://img.kisti.re.kr/originalView/originalView.jsp?url=/soc_img/society//calsec/KJGRBH/2003/v8n3/KJGRBH_2003_v8n3_165.pdf

n  개인 휴대단말에서 응용 프로그램 동기화를 위한 자동설치 시스템의 설계 및 구현
http://img.kisti.re.kr/originalView/originalView.jsp?url=/soc_img/society//kips/JBCREI/2003/v10An6/JBCREI_2003_v10An6_685.pdf

n  시스템 보안성 향상을 위한 패치 관리 시스템 설계 및 구현
http://img.kisti.re.kr/originalView/originalView.jsp?url=/soc_img/society//kias/SOBTCQ/2004/v4n2/SOBTCQ_2004_v4n2_43.pdf

n  안전한 보안패치 분배 구조의 설계 및 구현
http://img.kisti.re.kr/originalView/originalView.jsp?url=/soc_img/society//kiisc/JBBHCB/2003/v13n4/JBBHCB_2003_v13n4_47.pdf

n  보안패치 자동분배를 위한 패치 DB 자동구성 방안
http://img.kisti.re.kr/originalView/originalView.jsp?url=/soc_img/society//kiss/JBGHAN/2004/y2004m04a/JBGHAN_2004_y2004m04a_367.pdf

n  XML 기반 윈도우 보안패치 자동관리 시스템
http://img.kisti.re.kr/originalView/originalView.jsp?url=/soc_img/society//kiss/JBGHAN/2005/y2005m11a/JBGHAN_2005_y2005m11a_13.pdf

n  멀티플래폼을 지원하는 패치 자동관리 시스템
http://img.kisti.re.kr/originalView/originalView.jsp?url=/soc_img/society//kiss/JBGHAN/2003/y2003m10a/JBGHAN_2003_y2003m10a_889.pdf



 하둡/클라우드 관련

      

      l Hyperspace

             n 분산 락 서비스 지원

  l  Pig

n  대규모 데이터셋을 탐색하기 위한 프레임워크로 스크립트를 통해서 맵리듀스 기능을 수행

l  Hive

n  HDFS(컴퓨터들로 구성된 클러스터에서 수행되는 분산파일 시스템) 에 저장된 데이터를 관리할 수 있도록 쿼리를 제공하는 데이터 웨어하우스 프로젝트

l  Chukwa

n  분산환경에서의 로그 수집 및 저장을 위한 오픈소스 프로젝트

l  Zookeeper (분산환경 고가용성과 락킹 등 지원)

n  분산 응용 프로그램들을 구축하기 위한 고성능을 보장하기 위한 서비스로 분산 환경에서 노드들간의 정보공유, , 이벤트 등 보조 기능을 수행

n  http://creatorw.tistory.com/entry/2-%EC%A3%BC%ED%82%A4%ED%8D%BCzookeeper-%EA%B8%B0%EB%B3%B8-%EA%B5%AC%EC%A1%B0

n  zookeeper 운영시 권장사항
http://flutia.wordpress.com/2012/01/19/zookeeper-%EC%9A%B4%EC%98%81%EC%8B%9C-%EA%B6%8C%EC%9E%A5-%EC%82%AC%ED%95%AD/

n  zookeeper 세션, api option등 정리
http://pizzastudio.tistory.com/5

n   

l  HBase

n  하둡의 데이터베이스이다. 빅데이터에 접근, 실시간 임의의 읽기/쓰기에 필요하다. 대규모 데이터처리에 쓰인다.

l  NoSQL, 카산드라, 몽고DB, CouchDB 등등

n  관계형 데이터베이스의 확장성 한계와 클라우드 컴퓨팅에 맞지 않아 설계된 데이터베이스로 키와 값만을 쌍으로 가진 데이터베이스이다. 확장성이 좋지만 데이터 무결성, 정합성을 보장해주지 않는다.


l  nosql 도대체 어떻게 선택해야 할까?

n  http://kimws.wordpress.com/2012/02/26/nosql-%EB%8F%84%EB%8C%80%EC%B2%B4-%EC%96%B4%EB%96%BB%EA%B2%8C-%EC%84%A0%ED%83%9D%ED%95%B4%EC%95%BC-%ED%95%A0%EA%B9%8C/


http://www.techtoolblog.com/archives/195-free-online-programming-books

http://www.freeprogrammingebooks.net


Update - Update.. This List has Grown to 345…

Update: - I will be updating this list very shortly, many of the links were taken from http://www.programmingebooks.tk/

How to Be a Programmer 
http://samizdat.mines.edu/howto/HowToBeAProgrammer.html
How to Design Programs 
http://www.htdp.org/2002-09-22/Book/
Practical Theory of Programming 
http://www.cs.toronto.edu/%7Ehehner/aPToP/
Software Engineering for Internet Applications 
http://philip.greenspun.com/seia/
Structure and interpretation of computer programs 
http://mitpress.mit.edu/SICP/
More programming books http://2020ok.com/3839.htm
The Programmers Stone 
http://www.reciprocality.org/Reciprocality/r0/
Subversion Version Control: Using the Subversion Version Control System in Development Projects 
http://www.phptr.com/promotions/promotion….84&redir=1&rl=1

Ada

Ada 95 Rational 
http://www.adaic.org/standards/95rat/RATht…5-contents.html
Ada 95 Reference Manual 
http://www.adahome.com/rm95/
Changes to Ada 1987 - 1995 
http://www.oopweb.com/Ada/Documents/Change…lumeFrames.html
Ada 95: The Lovelace Tutorial 
http://www.adahome.com/Tutorials/Lovelace/master.htm
The Big Online Book of Linux Ada Programming 
http://www.pegasoft.ca/resources/boblap/book.html

Algorithms

Algorithms and Complexity 
http://www.cis.upenn.edu/%7Ewilf/AlgComp.html
Programming Algorithms http://2020ok.com/3870.htm
Information Theory, Inference, and Learning Algorithms 
http://www.inference.phy.cam.ac.uk/mackay/itprnn/book.html

Assembly

Assembly Language Tutorial 
http://www.oopweb.com/Assembly/Documents/a…lumeFrames.html
Programming From the Ground Up 
http://download.savannah.gnu.org/releases/pgubook/
Assembly Language Programming http://2020ok.com/3954.htm
Ralph Brown's Interrupt List 
http://www.oopweb.com/Assembly/Documents/I…lumeFrames.html
The Art of Assembly Language Programming 
http://www.oopweb.com/Assembly/Documents/A…lumeFrames.html
The Assembly Language Database 
http://www.oopweb.com/Assembly/Download/NortonGuide.zip
Win32 Programming for x86 Assembly Language Programmers 
http://www.oopweb.com/Assembly/Documents/W…lumeFrames.html

C

A Tutorial on Pointers and Arrays in C 
http://www.oopweb.com/CPP/Documents/CPoint…lumeFrames.html
C Programming 
http://www.oopweb.com/CPP/Documents/CProgr…lumeFrames.html
Object Orientated Programming in ANSI-C 
http://www.planetpdf.com/developer/article…?contentid=6635
The C Book 
http://publications.gbdirect.co.uk/c_book/
Writing Bug-Free C Code 
http://www.duckware.com/bugfreec/index.html
C - Elements of Style 
http://www.computer-books.us/c_3.php
Learning GNU C 
http://www.linuxtopia.org/online_books/pro…nu_c/index.html

C++

An Overview Of The C++ Programming Langauge 
http://www.oopweb.com/CPP/Download/crc.zip
C++ Annotations 
http://www.oopweb.com/CPP/Documents/CPPAnn…lumeFrames.html
C++ Annotations 
http://www.oopweb.com/CPP/Download/cplusplus.zip
C++ Coding Standard 
http://www.oopweb.com/CPP/Documents/CodeSt…lumeFrames.html
C & C++ http://2020ok.com/3956.htm
C++ Course 
http://www.oopweb.com/CPP/Download/CPPCourse.zip
C++ How To 
http://www.oopweb.com/CPP/Documents/CPPHOW…lumeFrames.html
C++ In Action 
http://www.relisoft.com/book/index.htm
C++: A Dialog 
http://www.steveheller.com/cppad/cppad.htm
How To Think Like A Computer Scientist with C++ 
http://www.oopweb.com/CPP/Documents/ThinkC…lumeFrames.html
Introduction To OOP Using C++ 
http://www.oopweb.com/CPP/Documents/Intro2…lumeFrames.html
Introduction To OOP Using C++ 
http://www.oopweb.com/CPP/Download/Intro2OOP.zip
Objects First 
http://www.oopweb.com/CPP/Documents/Object…lumeFrames.html
Optimizing C++ 
http://www.steveheller.com/opt/
STL Guide 
http://www.oopweb.com/CPP/Documents/STLGui…lumeFrames.html
STL Guide 
http://www.oopweb.com/CPP/Download/stl.zip
The Function Pointer Tutorials 
http://www.oopweb.com/CPP/Documents/Functi…lumeFrames.html
The Standard Template Library Tutorial 
http://www.oopweb.com/CPP/Documents/STL/VolumeFrames.html
Thinking in C++ 
http://www.planetpdf.com/developer/article…?ContentID=6634
Thinking in C++, Second Edition (Volumes 1 & 2) 
http://mindview.net/Books/TICPP/ThinkingInCPP2e.html
An Introduction to C++ Programming 
http://www.computer-books.us/cpp_1.php
Programming in C++ - Rules and Recommendations 
http://www.computer-books.us/cpp_6.php
A Beginners C++ Book 
http://www.uow.edu.au/~nabg/ABC/ABC.html

C++ GUI Programming with Qt 3 
http://www.phptr.com/promotion/1484?redir=1
Cross-Platform GUI Programming with wxWidgets 
http://www.phptr.com/promotion/1484?redir=1

C#

C# in Detail 
http://www.computer-books.us/csharp_0005.php
C# - The Basics 
http://www.computer-books.us/csharp_0004.php
C# Language Specification 
http://www.computer-books.us/csharp_1.php
Data Structures and Algorithms with Object-Oriented Design Patterns in C# 
http://www.computer-books.us/csharp_2.php
C# Programming http://2020ok.com/697342.htm
Dissecting a C# Application - Inside SharpDevelop 
http://www.computer-books.us/csharp_3.php
C# tutorial (2 .pdf's) 
http://www.ssw.uni-linz.ac.at/Teaching/Lec…Sharp/Tutorial/

CGI

CGI Programming on the World Wide Web 
http://www.oreilly.com/openbook/cgi/
CGI Programming http://2020ok.com/4025.htm

COBOL

zingCOBOL - A Beginners Guide to COBOL Programming 
http://www.computer-books.us/cobol_0006.php
Teach Yourself COBOL in 21 Days 
http://www.computer-books.us/cobol_0005.php
WebSphere Studio COBOL for Windows - Language Reference 
http://www.computer-books.us/cobol_1.php
COBOL Programming Course 
http://www.computer-books.us/cobol_2.php
COBOL Programming http://2020ok.com/3969.htm
WebSphere Studio COBOL for Windows - Programming Guide 
http://www.computer-books.us/cobol_3.php
HP COBOL II/XL Reference Manual 
http://www.computer-books.us/cobol_4.php

Databases

MySQL Reference Manual 
http://dev.mysql.com/doc/
Database http://2020ok.com/549646.htm
Oracle 10g Database Book and Documentation Library 
http://wtcis.wtamu.edu/oracle/

Delphi/Pascal

Delphi 2005 Tutorial for Beginners 
http://www.xcalibur.co.uk/training/Delphi2005/index.php
Delphi Training 
http://www.xcalibur.co.uk/training/delphi/oldindex.html
Essential Delphi 
http://marcocantu.com/edelphi/default.htm
Essential Pascal 
http://marcocantu.com/epascal/default.htm
Delphi Language Guide - Delphi For The Microsoft .NET Framework 
http://www.computer-books.us/delphi_2.php
Delphi Database Application Developers Guide 
http://www.computer-books.us/delphi_1.php

Fortran

Numerical Recipes with Fortran 77 
http://www.library.cornell.edu/nr/cbookfpdf.html
Numerical Recipes with Fortran 90 
http://www.library.cornell.edu/nr/cbookf90pdf.html
Professional Programmer's Guide to Fortran 77 
http://www.computer-books.us/fortran_3.php
User Notes on Fortran Programming (UNFP) 
http://www.ibiblio.org/pub/languages/fortran/

HTML

HTML 4.01 Specifications 
http://www.oopweb.com/HTML/Documents/HTML4/VolumeFrames.html
Web Development http://2020ok.com/3510.htm
Writing HTML 
http://www.oopweb.com/HTML/Documents/Writi…lumeFrames.html

Java

How to Think Like a Computer Scientist with Java 
http://www.oopweb.com/Java/Documents/Think…lumeFrames.html
Introduction to Programming Using Java 
http://www.oopweb.com/Java/Documents/Intro…lumeFrames.html
Introduction To Programming Using Java 
http://www.linuxtopia.org/online_books/pro…ming/index.html
Java Programming Tutorial: Introduction to Computer Science 
http://www.oopweb.com/Java/Documents/JavaN…lumeFrames.html
Thinking in Java, 3rd Edition 
http://www.mindview.net/Books/TIJ/
Thinking in Enterprise Java 
http://www.ibiblio.org/pub/docs/books/eckel/
More Java Books http://kickjava.com/freeBooks.html
Java AWT Reference 
http://www.oreilly.com/catalog/javawt/book/index.html
Enterprise JavaBeans 
http://www.computer-books.us/java_1.php
Essentials of the Java Programming Language - Part 1 
http://www.computer-books.us/java_2.php
Essentials of the Java Programming Language - Part 2 
http://www.computer-books.us/java_3.php
Exploring Java 
http://www.computer-books.us/java_4.php
Introduction to Computer Science using Java 
http://www.computer-books.us/java_5.php
Java Development http://2020ok.com/3608.htm
Java Language Reference 
http://www.computer-books.us/java_8.php
Java Servlet Programming 
http://www.computer-books.us/java_9.php
Java Web Services Tutorial 
http://www.computer-books.us/java_10.php
Java Look and Feel Design Guidelines, Second Edition 
http://java.sun.com/products/jlf/ed2/book/index.html
The Design Patterns: Java Companion 
http://www.patterndepot.com/put/8/JavaPatterns.htm
1000 Java Tips e-Book 
http://javaa.com
Apache Jakarta Commons: Reusable Javaâ„¢ Components 
http://www.phptr.com/promotion/1484?redir=1
Javaâ„¢ Application Development on Linux® 
http://www.phptr.com/promotion/1484?redir=1
Practical Artificial Intelligence Programming in Java 
http://www.markwatson.com/opencontent/javaai_lic.htm

Javascript

Voodoo's Introduction to Javascript 
http://www.oopweb.com/JavaScript/Documents…lumeFrames.html
Javascript Programming http://2020ok.com/3617.htm

Linux

Linux Device Drivers, Third Edition 
http://lwn.net/Kernel/LDD3/
The Linux Development Platform 
http://www.phptr.com/promotion/1484?redir=1
Understanding the Linux Virtual Memory Manager 
http://www.phptr.com/promotion/1484?redir=1
Self-Service Linux®: Mastering the Art of Problem Determination 
http://www.phptr.com/promotion/1484?redir=1
Linux® Quick Fix Notebook 
http://www.phptr.com/promotion/1484?redir=1
Managing Linux Systems with Webmin: System Administration and Module Development 
http://www.phptr.com/promotion/1484?redir=1
An Introduction to GCC 
http://www.linuxtopia.org/online_books/an_…_gcc/index.html
Linux http://2020ok.com/3756.htm
Using the GNU Compiler Collection (GCC)

http://www.linuxtopia.org/online_books/pro…tion/index.html
Bash Reference Guide 
http://www.linuxtopia.org/online_books/bas…uide/index.html
Bash Guide for Beginners 
http://www.linuxtopia.org/online_books/bas…ners/index.html
Advanced Bash Scripting Guide 
http://www.linuxtopia.org/online_books/adv…uide/index.html
Linux Kernel Module Programming Guide 
http://www.linuxtopia.org/online_books/Lin…uide/index.html
Red Hat Linux Developer Tools Guide 
http://www.linuxtopia.org/online_books/red…uide/index.html
Linux Debugging with gdb Guide 
http://www.linuxtopia.org/online_books/red…_gdb/index.html
Using cpp, the C Preprocessor Guide 
http://www.linuxtopia.org/online_books/pro…ssor/index.html

Lisp

Loving Lisp - the Savy Programmer's Secret Weapon 
http://www.markwatson.com/opencontent/lisp_lic.htm
List Programming http://2020ok.com/3981.htm

Open Source

Rapid Application Development with Mozilla 
http://www.phptr.com/promotion/1484?redir=1
Creating Applications with Mozilla 
http://books.mozdev.org/chapters/index.html
Free as in Freedom 
http://www.oreilly.com/openbook/freedom/index.html
Managing Projects with GNU make, 3rd Edition 
http://www.oreilly.com/catalog/make3/book/index.csp
OpenSources: Voices from the Open Source Revolution 
http://www.oreilly.com/catalog/opensources/book/toc.html
Understanding Open Source and Free Software Licensing 
http://www.oreilly.com/catalog/osfreesoft/book/
Embedded Software Development with eCos 
http://www.phptr.com/promotion/1484?redir=1
Open Source Security Tools: A Practical Guide to Security Applications 
http://www.phptr.com/promotion/1484?redir=1

Perl

HTMLified Perl 5 Reference Guide 
http://www.oopweb.com/Perl/Documents/Perl5…lumeFrames.html
Perl 5 Documentation 
http://www.oopweb.com/Perl/Documents/PerlD…lumeFrames.html
Perl for Perl Newbies 
http://www.oopweb.com/Perl/Documents/P4PNe…lumeFrames.html
Perl for Win32 FAQ 
http://www.oopweb.com/Perl/Documents/PerlW…lumeFrames.html
Picking Up Perl 
http://www.oopweb.com/Perl/Documents/Picki…lumeFrames.html
Picking Up Perl 
http://www.linuxtopia.org/online_books/perl/index.html
Perl Programming 
http://www.2020ok.com/4045.htm
Practical Perl Programming 
http://www.oopweb.com/Perl/Documents/ppp/VolumeFrames.html
Beginning Perl 
http://www.perl.org/books/beginning-perl/
Impatient Perl 
http://www.perl.org/books/impatient-perl/
Extreme Perl 
http://www.extremeperl.org/bk/home
MacPerl: Power & Ease 
http://macperl.com/ptf_book/r/MP/i2.html
Embedding Perl in HTML with Mason 
http://www.masonbook.com/
Perl for the Web 
http://www.globalspin.com/thebook/
Practical mod_perl (1st edition) 
http://modperlbook.com/
Web Client Programming with Perl 
http://www.oreilly.com/openbook/webclient/
Perl 5 By Example 
http://www.computer-books.us/perl_0010.php
An Introduction to Perl 
http://www.linuxtopia.org/Perl_Tutorial/index.html

PHP

Practical PHP Programming 
http://www.hudzilla.org/phpbook/
A Programmer's Introduction to PHP 4.0 -http://www.apress.com/free/
PHP 5 Power Programming 
http://www.computer-books.us/php_2.php
PHP Programming http://2020ok.com/295223.htm
Practical PHP Programming 
http://www.computer-books.us/php_3.php

Prolog

Adventure in Prolog 
http://www.amzi.com/AdventureInProlog/
Building Expert Systems in Prolog -http://www.amzi.com/ExpertSystemsInProlog/
Prolog programming http://2020ok.com/295223.htm 
Prolog Programming A First Course 
http://computing.unn.ac.uk/staff/cgpb4/prologbook/

Python

Non-Programmers Tutorial for Python 
http://rupert.honors.montana.edu/~jjc/easy…ut/easytut.html
Official Python Documentation 
http://www.python.org/doc/current/
Text Processing in Python -http://gnosis.cx/TPiP/
Python Reference Manual 
http://docs.python.org/ref/ref.html
Python Imaging Library Handbook -http://www.pythonware.com/library/the-python-imaging-library.htm
How to Think Like a Computer Scientist - Learning with Python 
http://www.greenteapress.com/thinkpython
Dive Into Python -http://diveintopython.org/
Python Programming http://2020ok.com/285856.htm
Thinking in Python 
http://mindview.net/Books/TIPython
A Byte of Python 
http://www.ibiblio.org/g2swap/byteofpython/read/

Ruby

Programming Ruby - The Pragmatic Programmer's Guide (First Edition) 
http://www.ruby-doc.org/docs/ProgrammingRuby/
Why's (Poignant) Guide to Ruby 
http://poignantguide.net/ruby/ <–the funniest programming book I have ever seen!

Samba

Samba-3 by Example: Practical Exercises to Successful Deployment 
http://www.phptr.com/promotion/1484?redir=1
Samba-3 by Example: Practical Exercises to Successful Deployment, 2nd Edition 
http://www.phptr.com/promotion/1484?redir=1
The Official Samba-3 HOWTO and Reference Guide 
http://www.phptr.com/promotion/1484?redir=1
Implementing CIFS: The Common Internet File System 
http://www.phptr.com/promotion/1484?redir=1

SQL

Comparison of Different SQL Implementations 
http://www.computer-books.us/sql_0004.php
SQL - A Practical Introduction 
http://www.managedtime.com/freesqlbook.php3
Introduction To Structured Query Language 
http://www.computer-books.us/sql_2.php
Practical PostgreSQL 
http://www.opendocspublishing.com/ppbook/

UNIX

FreeBSD Handbook 
http://www.freebsd.org/doc/en_US.ISO8859-1…book/index.html
Unix http://2020ok.com/3778.htm
The UNIX-HATERS Handbook 
http://research.microsoft.com/%7Edaniel/unix-haters.html

Visual Basic and VB.net

Programming VB.NET - A Guide For Experienced Programmers 
http://www.apress.com/free/
Upgrading Microsoft Visual Basic 6.0 to Microsoft Visual Basic .NET 
http://msdn.microsoft.com/vbrun/staythepat…s/upgradingvb6/
Visual Basic http://2020ok.com/3996.htm
Introducing Visual Basic 2005 for Developers
http://msdn.microsoft.com/vbrun/staythepat…05/default.aspx

XML

OpenOffice.org XML Essentials 
http://books.evc-cit.info/

Misc. stuff that is worth reading

FREE Trade Magazine Subscriptions & Technical Document Downloadshttp://i.nl03.net/ltr0/?_m=01.009i.nv.mfm.nv
The Future does not compute 
http://www.praxagora.com/stevet/fdnc/toc.html
The Cathedral and the Bazaar 
http://www.catb.org/~esr/writings/cathedral-bazaar/

사전적 의미 : 
1. (크기・양・범위 등을) 제한하다
2. (자유로운 움직임을) 방해하다
3. (규칙・법으로) 제한하다


C 언어에서 의미 : 
restrict 키워드는 오직 포인터에만 적용되는 키워드로 그 포인터가 데이터 객체에 접근할수 있는 유일하고도 최초가 되는 수단임을 나타낸다. 즉 포인터가 restrict로 한정되면 그 포인터가 가리키는 데이터 블록은 그 포인터만이 접근이 가능하다.(같은 SCOPE(쉽게 생각하면 '{' '}' 블럭 안) 상에서)


예를 들어 

strcpy() 함수는 

char * strcpy (char *restrict to, const char *restrict from) 형태를 갖는다.

이것은 strcpy 함수 내에서는 to와 from 이 가르키는 데이터블럭은 자기자신만 접근가능하다는 소리이다.

즉. to 와 from 은 같은 주소가 될수 없다는 말을 명시적으로 해준것이다.


참고 : http://msdn.microsoft.com/ko-kr/library/5ft82fed.aspx

참고 :

'Restrict' Pointers

One of the new features in the recently approved C standard C99, is the restrict pointer qualifier. This qualifier can be applied to a data pointer to indicate that, during the scope of that pointer declaration, all data accessed through it will be accessed only through that pointer but not through any other pointer. The 'restrict' keyword thus enables the compiler to perform certain optimizations based on the premise that a given object cannot be changed through another pointer. Now you're probably asking yourself, "doesn't const already guarantee that?" No, it doesn't. The qualifier const ensures that a variable cannot be changed through a particular pointer. However, it's still possible to change the variable through a different pointer. For example:

 

  void f (const int* pci, int *pi;); // is *pci immutable?
  {
    (*pi)+=1; // not necessarily: n is incremented by 1
     *pi = (*pci) + 2; // n is incremented by 2
  }
  int n;
  f( &n, &n);
 

In this example, both pci and pi point to the same variable, n. You can't change n's value through pci but you can change it using pi. Therefore, the compiler isn't allowed to optimize memory access for *pci by preloading n's value. In this example, the compiler indeed shouldn't preload n because its value changes three times during the execution of f(). However, there are situations in which a variable is accessed only through a single pointer. For example:

 

  FILE *fopen(const char * filename, const char * mode);

The name of the file and its open mode are accessed through unique pointers in fopen(). Therefore, it's possible to preload the values to which the pointers are bound. Indeed, the C99 standard revised the prototype of the function fopen() to the following:

 
  /* new declaration of fopen() in <stdio.h> */
  FILE *fopen(const char * restrict filename, 
                        const char * restrict mode);

Similar changes were applied to the entire standard C library: printf(), strcpy() and many other functions now take restrict pointers:

 
  int printf(const char * restrict format, ...);
  char *strcpy(char * restrict s1, const char * restrict s2);

C++ doesn't support restrict yet. However, since many C++ compilers are also C compilers, it's likely that this feature will be added to most C++ compilers too


출처 : http://www.pmguda.com/72


디버깅은 프로그래밍을 시작하는 사람이면 누구나 동시에 시작하는 작업입니다. 디버깅을 시작하는 사람들을 위해 프로그래밍을 시작하는 처음부터 어떤 태도를 가져야 할 지, 어떤 것을 알아야 할 지 알아보도록 하겠습니다. 대중적인 플랫폼을 크게 두 개로 보았을 때, 디버깅은 윈도우 계열과 유닉스 계열의 큰 차이는 없습니다. 다만, 그 툴이 현저히 달라서 두 계열 동시에 비슷한 기능을 하는 디버깅 툴을 소개한다는 것은 불가능한 일입니다. 하지만 프로그램을 작성할 때부터 디버깅을 염두에 두고 프로그램을 작성하는 면에서는 크게 다르지 않습니다. 이 글에서는 프로그램이 만들어지는 순간들을 살펴보면서, ‘디버깅을 위한 프로그래밍 습관’에 대해 모든 환경에서 주의해야할 디버깅 기법에 대해 정리하고자 합니다. 참고로, 필자는 유닉스 기반의 서버 프로그램을 작성 및 포팅하는 것을 전문으로 하고 있습니다. 디버깅을 너무 일반적으로 할 수는 없는 것이므로, 연재를 통틀어 C/C++를 기반으로 전개할 것입니다.

언어와 개발 환경
다음의 몇 가지 이야기는 디버깅을 잘하는 것은 올바른 배움의 자세에서 나온다는 것을 전제로 생각해 보기 위한 글입니다.
반쪽 프로그래머
프로그래밍을 처음 배우는 사람은 C++, 자바, HTML 등을 배우게 됩니다. 즉, 언어를 배우게 되는 것이죠. 여기에 디버깅을 생각하면, 참으로 뛰어넘기 어려운 커리큘럼의 한계에 부딪히게 됩니다. 배울 때는 언어만 배우면 될 것 같지만 언어의 문법을 익히는 것만으로는 50점입니다. 그와 쌍벽을 이루는 것은 환경이라 할 수 있습니다. 즉 OS, 프로토콜, 라이브러리 등을 말합니다. 실전에서 부딪히는 ‘디버깅의 문제’는 항상 언어와 환경에 대한 이해도를 동시에 측정하는 문제와 같습니다. 어느 하나만 물어보는 문제는 사실 그리 많지 않습니다. 문법을 익히는 것으로도 어려운 사람에게 OS와 원하는 환경에 대한 API들(소켓, DB, 멀티미디어, MAPI, IPC 등)을 익혀야 한다는 사실은 프로그래머의 길을 참으로 멀게 느껴지게 하는 요소가 됩니다. 하지만 진실을 알아야 제대로 길을 가겠지요.
창을 제어하는 것을 만들 때, MFC를 사용할 것이냐와 볼랜드의 OWL을 사용하느냐는 ‘라이브러리’의 문제가 됩니다. 물론 컴파일러와 동반된 라이브러리라는 점에서는 ‘컴파일러’의 문제일 수도 있습니다만, 좀더 멀리 윈도우와 유닉스 계열에 동시 사용되는 Qt 라이브러리를 사용하느냐, 유닉스 상에서 사용되는 구식의 Motif 라이브러리를 사용할 것이냐 등의 문제까지 확장한다면, 이들을 사용할 때의 언어는 C/C++를 통해 비슷한 문법을 사용하지만 ‘사용되는 OS 플랫폼’과 ‘라이브러리’의 문제가 됩니다.
중요한 것은 언급한 OS와 컴파일러 등에 따라 라이브러리를 선택해야만 하지만, 이들 라이브러리들이 만들어지게 된 동기나 UI 및 처리 방식 등은 비슷하다는 것입니다. OS, 컴파일러, 라이브러리는 상호 호환되지 않지만 시작과 끝은 비슷한 인터페이스와 구현 개념으로 시작해 C/C++라는 언어까지 비슷한 체계를 만들어 냅니다. 이런 유사성이 많은 라이브러리가 있다는 것은 알지만 그것을 공부하는 것은 어렵습니다. 그럴지라도 빠지지 말아야 할 오류 중의 하나는, 언어와 라이브러리의 정확한 경계를 파악하면서 배우자입니다.
흔히 잘못 알려진 예를 들어보기로 합시다. 웹 프로그래밍을 할 때, ASP는 사실 IIS에서 CGI를 잘 구현하기 위한 몇 가지 객체에 대한 정의입니다. 그 객체는 언어와 독립된 존재입니다. 따라서 VBScript는 ASP와 분리되어 생각해야 하지요. JScript로 ASP를 작성할 수도 있습니다. 그러나 ‘ASP로 만들었어’라는 말에는 ‘VBScript로 만들었어’를 함축하여 사용하게 됩니다. 언어와 환경을 분리해 공부하는 학습을 해 두는 것이 앞서 언급한 언어와 환경을 동시에 묻는 ‘디버깅 문제’를 잘 해결하는 지름길입니다.

언어와 표준 라이브러리
주로 C, C++를 배울 때 나오는 문제입니다. 사실 C 언어와 동시대에 만들어지고 살아남은 언어는 없다고 해도 과언이 아닐 정도입니다. C 언어는 그간 많은 정제 작업을 거쳐 표준화되었고, 어떤 플랫폼이 새로 나올 때 어셈블리 다음으로 가장 먼저 포팅이 되는 언어라 할 수 있습니다. 그만큼 언어를 통해 이루어 놓은 재원이 풍부하다는 것이지요. 요즘에 새로이 나오는 언어들은 대개 표준화된 라이브러리를 포함해 배포가 됩니다. 하지만 C는 표준화 작업에서 ‘C 라이브러리’라는 표준화된 라이브러리를 선택하게 되었고, 컴파일러는 표준 C 라이브러리와 OS 자체 라이브러리를 동시에 배포하게 됩니다. 그러다보니 처음 언어를 배우는 사람들이 문법과 라이브러리의 차이를 알면서 배우기란 참 힘듭니다.
for와 printf 예를 들어 봅시다. for는 C 언어를 이루는 구문이며, printf는 라이브러리 함수라는 큰 차이가 있습니다. 이러한 차이는 처리 관점에서 볼 때, for는 컴파일러가 해석해 루프 코드를 만들어 내고, printf에 대해서는 심볼을 찾아 호출(call)할 수 있는 방법으로 처리됩니다. 링커는 for에 대해서는 아무것도 하지 않으며, printf에 대해서는 외부 라이브러리에서 심볼을 찾아다가 점프 테이블을 갱신해 줍니다. printf는 C 언어 문법 명세에 있는 것이 아닙니다. 표준 라이브러리에 들어 있는 것입니다. sizeof는 함수인가요? 연산자입니다. 의심스러운 분은 찾아보기 바랍니다. printf의 구현은 DOS에서 다르고, MS 윈도우에서 다르고, 모바일 폰에서 다릅니다. 하지만 C 표준 문서는 printf의 선언에 대한 명확한 정의를 하고 있습니다. C가 놀라운 이식성을 가진다는 것은 플랫폼이 기본적으로 지원하는 언어이며, 지원시 표준 라이브러리 명세에 들어 있는 것을 해당 플랫폼에 맞게 구현해 놓았다는 것에 있습니다. 다시 한번 디버깅을 위한 기본 자세는 언어와 환경을 잘 구별하는 것에 있음을 강조하고 싶습니다.

#구문과 함수
#include
int main( void ) /* main : 라이브러리 함수 */
{
int i;
for( i=0; i<10; i++ )
{
printf("%d Hello, world? %d", i, sizeof( i ) );
} /* printf : 라이브러리 함수, sizeof : 연산자) */
return 0; /* return : 구문 */
}

요즘의 에디터는 함수와 구문/연산자에 대해 색깔을 다르게 표시해 줍니다. 구문 컬러링(syntax coloring)은 90년대 초반 볼랜드의 터보 C++ 이후로 프로그램 소스 에디터의 거의 필수적인 요소가 되어 있습니다. 유닉스에서도 Emacs와 vim을 쓰는 분들도 구문 컬러링을 위해 컬러가 지원되는 터미널 혹은 GUI 버전을 사용하는 것이 추세입니다. <리스트 1>을 보면, 구문 컬러링이 main에 대해서는 printf와 같이 하는 것을 보기도 할 텐데요. main은 단순한 콜백 함수일 뿐입니다. C 언어는 C start-up object가 있어서 OS에서 프로세스를 실행할 때 초기화하는 코드가 먼저 불려지고, 이 코드는 main이라는 외부 함수를 호출하게 되어 있습니다. 따라서 외부 프로그램은 항상 main부터 시작하게 되는 것이지요. 이것은 링커의 규약이 아니며, 단지 C start-up object에서 그것을 요구하기 때문일 뿐입니다. 링커는 C 언어와는 상관없이 객체간에 undefined symbol에 대해 다른 라이브러리나 객체에서 익스포트 심볼을 찾아 채워주는 일을 합니다.
<리스트 1>에서 sizeof를 잘 살펴보면, sizeof가 함수일 경우 그것은 링커에 의해 관심 대상이 될 것입니다. 하지만 sizeof는 컴파일 타임에서 그 값이 결정되는 단항 연산자이며, 결과는 상수입니다. 즉, 프로그램 중간에 바뀌지 않는다는 것이지요.


OS 편애 금지
모름지기 프로그래머라면, 플랫폼과 언어 선택에 있어서 운신의 폭을 좁히는 것은 ‘깊은 이해’를 끊는 것이나 다름없습니다. 종종 비아냥 투로 이런 류의 얘기를 많이 듣습니다. “앞으로도 성공할 리 없는 리눅스는 관심 없어. 난 윈도우 프로그래머니까”, “툭하면 파란 화면 뜨는 것이 OS냐?” 이런 플랫폼 고착적인 자세는 프로그래머로서의 도리가 아닙니다. 프로그래머는 플랫폼을 가리지 말고 도전할 때 운용체계와 라이브러리에 대한 깊은 이해가 생기게 됩니다. 모든 OS는 나름대로의 위치가 있습니다. 나름대로의 노하우를 정리해 두는 것이 앞으로 30년 뒤에 나올 OS도 문제없이 프로그래밍할 대상이 될 수 있을 것입니다. 앞으로 20년 뒤, “내가 xxx와 yyy에서 20년간 프로그래밍을 해보니 yyy는 OS로서는 미흡하다”는 말을 할 수 있기를 바랍니다. 디버깅을 잘하는 사람의 특징은 플랫폼과 라이브러리에 대한 겸손과 섬세한 이해라고나 해야 할까요?

API에 대한 경외심과 답답함
디버깅 초보가 겪는 문제 중의 하나는 널리 알려진 API에 대한 경외심 혹은 그 반대의 답답함에 있습니다. API라는 것은 말 그대로 Application Programming Interface입니다. 블랙박스를 사용하는 방법에 대한 문서라고 할 수 있습니다. API에 대한 경외심은 개발자가 잘 모르는 영역에 대한 API인 경우가 많습니다. 파일 시스템 핸들링 API, 윈도우 메시지 API, 프로세스간 데이터 교환을 돕기 위한 IPC 등 시스템 레벨인 경우에는 안정적일 것이라는 막연한 생각에서 인정하고 사용합니다.
반면, 답답함은 버그가 발생하고, 문제가 없을 듯해 보이는 방법이 전혀 해결될 기미가 보이지 않을 때 일단 자신의 실력을 의심하다가 나중에는 API에 버그가 있을지도 모른다는 생각을 하게 됩니다. 특히, 최근에 나온 소프트웨어에 대한 것일수록 그런 의심을 하게 됩니다. “소스를 알면 쉽게 디버깅을 할 텐데”라는 체념은 많은 프로그래머의 공통적인 경험입니다만 대개의 공인된 API에 대한 답답함은 소스를 모르는 것에 있지 않고, 제대로 되어 있지 않은 샘플 없는 문서에 있을 것입니다. 이런 경우는 어쩔 수 없이 사용자 포럼의 도움 혹은 검색 엔진을 통한 도움을 받아야 합니다. 모르는 것일수록 샘플을 수집해 사용 예를 구해야 하고, 충분한 샘플 이해 없이 빈약한 문서만으로 시간을 낭비하지 맙시다.
API는 처음부터 완벽하지 않습니다. 그리고 문서도 완벽하지 않습니다. 아직도 수많은 OS의 Undocumented API들이 존재합니다. 어떤 경우든지(문서가 없든지, 문서를 이해 못했든지) API를 자신이 만든 수준으로 이해하지 못한 경우에는 버그가 존재하기 마련입니다.

몇 가지 바른 생활 - 딴짓하는 프로그래머
디버깅은 종합 예술 행위입니다. 전체적이고 섬세한 감각을 소유하지 않으면, 디버깅의 깊이가 그만큼 줄어들게 됩니다. 메모, 프로세스, 파일 I/O, 소켓, UI 등등 체계적인 지식이 없이는 해결되지 않는 경우가 많습니다. 소켓 문제인줄 알고 소켓 관련된 책만 읽다가 나중에는 쓰레드 문제로 판명되는 경우도 있습니다. 대개 디버깅은 의외로 사소한 것을 많이 알고 있을 때 쉽게 해결됩니다. 디버깅을 잘하는 사람은 사소한 것을 꼼꼼히 알고 있는 사람입니다. 그런 면에서 업무 외에 재미로 하는 ‘프로그래밍 딴짓(?)’은 그 사람의 잠재적인 문제해결력을 증강시키는 효과가 있습니다. 이는 결코 측정될 수 없는 능력입니다.
딴짓은 본디 체계가 없는 것이긴 하지만, 배움을 동기로 하는 딴짓은 딴짓 이상의 딴짓입니다. 다음은 필자가 해 보았거나, 쓸만한(?) 딴짓 목록을 적어 놓은 것입니다. 모두 유틸리티와 그것을 사용하는 스크립트입니다. 유명한 유틸리티와 스크립트 언어를 사용하는 것은 프로그래머의 자유도를 높여 줍니다.

【유닉스 계열】
1 접속 후 아무 일도 하지 않은 채 24시간 이상된 사용자 끊는 스크립트 작성해 보기 - w, awk, kill
2 수시로 디스크의 사용량을 확인하여 80% 이상 되었을 때 자동으로 메일 보내기 - df, awk, mail
3 스포츠 신문 만화를 긁어 친구들에게 메일로 보내기 - wget, perl, mail
4 주기적으로 내 특정 디렉토리 전체를 다른 서버로 복사하기 - rsync

【윈도우 계열】
1 조카들이 바꿔 놓는 IE의 시작 페이지를 부팅 후 레지스트리에 원래대로 해 놓기 - VBScript
2 회사내 로컬 IP - 호스트명 테이블 만들어 보기 - nbtstat, perl
3 회사내 공유 폴더 리스트 만들어 보기 - net, perl
* - 뒤는 사용됨 직한 유틸리티입니다

사용자의 눈, 개발자의 눈
여러분이 프로그래머라면 일반 사용자와 눈이 달라져야 합니다. 컴퓨터에서 일어나는 모든 세세한 일까지 호기심을 가지고, 나름대로의 추측을 가지고 있어야 하고, 나중에 문서를 통해 혹은 트레이서 등을 통해 추측을 확인해야 하고, 궁극적으로는 필요한 때에 정확히 재현할 수 있는 코드를 작성할 줄 알아야 합니다.
디버깅은 전문 디버거로 알려진 도구들만의 전유물이 아닙니다. 디버깅은 정상으로 실행되는 프로그램에 대한 이해부터 시작합니다. 응답 시간이 길어지는 프로그램을 잘 살펴보면,
으로 눌러 다른 화면에서 돌아올 때 창이 새로 그려지지 않는 경우가 있습니다. 또 자세히 보면 윈도우의 맨 가장자리 프레임은 항상 그려지게 됩니다. 왜 그럴까요? 일반 사용자의 관점과 달리 프로그래머의 관점에서 보면, 현재 응답을 기다리는 쓰레드가 내부 창을 그리는데 사용되는 것과 같다는 것을 추측할 수 있습니다. 윈도우 맨 가장자리를 다루는 쓰레드는 OS에 소속된 것이지, 응용 프로그램에 소속된 것이 아닐 것 같다는 생각도 해 볼 수 있습니다.
조금 더 얘기하면, 디스플레이 등록정보에는 ‘마우스로 끄는 동안 창 내용 표시’ 같은 기능이 있습니다. 또, MSN Plus에서 제공하는 광고 창 감추기 기능이 있습니다. 이런 것들은 Spy++ 같은 윈도우 메시지 트레이서 기능을 이용해 평소에 눈여겨 두면, 알고 있는 지식과 구현된 기능에 대한 실 예를 통해 폭넓은 이해가 가능합니다. 유닉스의 경우 리눅스의 strace, 솔라리스의 truss, hpux의 tusc 등을 이용해 평소에 inetd 같은 데몬이 어떻게 돌아가는지(option -p) 알아 볼 수 있습니다. 이들은 실행중인 프로그램에 큰 영향을 주지 않으면서, 엿보기 기능을 이용해 구현을 짐작해 보는 것들입니다. API가 아무리 블랙박스처럼 보여도, 평소에 이런 류의 툴을 이용해 시스템 레벨의 입출력을 덤프해 보는 것만으로 API의 내부를 어느 정도 짐작해 볼 수 있습니다. 물론, 리버스 엔지니어링은 많은 소프트웨어에서 금지되어 있다는 사실도 염두에 두면서 들여다보기 바랍니다.

재현 가능성
으례 들을 수 있는 말이지만, 디버깅은 사건을 추적하는 형사가 하는 일과 같습니다. 크게 다른 것은 디버깅은 언제든지 같은 상황을 재현할 수 있는 데 있으며, 형사가 하는 일은 단 한 번의 사건에 국한되어 비슷한 상황을 연출하는 데 그 한계가 있다고 볼 수 있습니다. 우리로서는 참으로 다행이지 않을 수 없습니다. 수만 번 프로세스가 죽고, core dump, watson log 같은 시체만 남는다 해도 윤리적인 가책을 전혀 느끼지 않으니까요. 디버깅을 하는 사람들은 형사처럼 조심스럽게 그 프로세스의 시체들을 디버거를 통해 부검하겠지요.
디버깅을 위한 전제 조건으로 ‘재현 가능성’을 생각해 보겠습니다. 누구한테 디버깅에 대한 조언을 구할 때에도 재현을 하기 위한 방법이 모호하고, 심지어 말을 들어 주는 사람도 증상을 유추하기 어렵다면 별 도움을 받을 수 없을 것입니다. 증상을 제대로 설명하지 않았는데도 답변을 바로 준다면, 그 사람은 아마 여러분의 그룹에서 경외의 대상일 것입니다. 비단, 프로그램뿐만 아니라 전화나 메신저를 통해 컴퓨터의 이상을 호소하는 사람에게 조차 처음 듣는 현상인 경우 그대로 재현할 수 있는 방법에 대해 들어야 올바른 답을 줄 수 있는 것입니다.
또 다른 측면에서 다른 사람에게 설명하기 위해 재현하는 방법을 차근차근 설명하다가 해결책을 아는 경우가 종종 있습니다. 끝까지 설명하지 않았는데 말이죠. 이전까지는 문제의 현상에만 집중한 나머지 처음부터 생각을 하지 않았던 것입니다. 아니, 문제가 다른 부분에 있을 것이라고는 생각하지 않았던 것입니다. 그만큼 어떤 문제가 ‘재현 가능한지’에 대한 것과 ‘어떻게 재현할 수 있는지’에 대한 것은 디버깅을 위한 전제 조건이 됩니다.
개발자와 QA가 분리되어 있는 개발 그룹의 경우, QA의 버그 리포트는 재현 순서에 대한 상세한 설명을 수반하게 됩니다. 또한, 고객 상담실이 운영되어 출시한 프로그램의 사용자 지원이 이뤄질 때도 버그 재현에 대한 상세한 문서가 먼저 선행 조건이 됩니다. ‘재현되지 않는 버그는 고칠 수 없습니다’ - 개발자가 좋아하는 문구입니다. 디버깅을 위한 다음과 같은 공동의 작업 환경이 있다면 훌륭한 팀이 됩니다.

1 소스 버전 컨트롤 : Visual Source Safe, CVS, WinCVS, TortoiseCVS
2 버그 게시판 혹은 회람용 문서 : 배포 버전 번호/테스트 수트, 방법/ 버그 재현 순서/개발자 의견/조치 이력
3 잦은 배포 : 수시로 (2주 이내) 소스 묶음과 설치본을 QA에 넘깁니다

코드 리뷰
디버깅은 아니지만 꼼꼼한 관리자는 개발이 어느 정도 완료된 후 코드 리뷰(code review)를 하자고 합니다. 개발자로서는 참으로 쑥스러운 시간입니다. 한 사람당 한두 시간 정도 들어 발표하는 동안, 지켜보는 모든 사람은 인공지능 컴파일러가 되어 올려지는 모든 소스를 날카롭게 보게 됩니다. 코딩 규칙이나 명료하지 않는 부분, 주석 없는 것이 들키는 시간이지요. 이 컴파일러는 경고가 친절하지 않습니다. 간혹 인간성이 안 좋은 컴파일러로부터 심한 말도 듣게 됩니다. 한 사람 때문에 팀 전체 소스의 신뢰도를 떨어뜨릴 수 있기 때문이죠. 코드 리뷰는 여러 가지 이점이 있지만, 중요한 것은 준비하면서 코드를 다듬게 되며 발표 중에는 개발자조차 간과했던 버그를 발견하는 것입니다.
리턴 값을 확인하지 않고 지나는 경로가 있는지, assert 조건이 있음에도 assert문이 빠져 있다든지, 배열에 대한 boundary 확인이 되지 않은 채 최대 인덱스를 넘어 사용하는 부분이 있다든지, 재현되지 않은 버그까지 발견할 수 있는 이점을 가져다 줍니다. 이런 내용은 다음에 다시 설명 드리겠습니다. 디버깅을 위?코드 리뷰는 다음과 같이 합니다.

【발표하는 경우】
1 구문 컬러링이 되어 있는 에디터를 통해 소스를 보여줍니다(ViewCVS를 사용할 경우 enscript 기능 추가)
2 에디터에서 직접 수정하거나 메모장을 이용해 논의사항을 추후 반영합니다
3 설계 문서를 간단히 준비해 보여줍니다
4 설계상 가장 중요한 구조체/클래스에 대한 헤더를 먼저 소개합니다
5 메인 루프, 즉 함수들을 호출하는 중심이 되는 함수를 먼저 소개합니다
6 설계 문서를 번갈아 가며 구현되어 있는 함수를 보여줍니다.

【듣는 경우】
1 코딩 규칙을 살펴봅니다
2 알고 있는 것과 반대되는 것, 특이한 구현 방식에 대해 질문합니다
3 컴파일러가 그러하듯 질문 내용을 바로 질문해 토의가 일방적이지 않게 합니다
4 추궁하여 당황하게 만들지 말고, 충분히 소개할 수 있는 편안한 자세를 만들어 줍니다

코드 리뷰는 팀 내에서만 이뤄지는 것이 아닙니다. 오픈소스 진영에서는 발표하는 순간부터 코드 리뷰가 이뤄지고 있습니다. 소스에 대한 접근 권한이 있다는 것은 코드리뷰가 진행 중이라는 것이며, 개발자는 다른 사람의 리뷰 결과에 대해 겸손한 피드백을 해주어야 합니다. 코드 리뷰는 디버깅과 튼튼한 코드를 위한 가장 매력적이며 가장 확실한 방법입니다.

남의 코드를 많이 보라
소스는 마치 책과 같아 좋은 소스와 나쁜 소스에 대한 구별법이 없이는 잘못된 습관을 만들 수 있습니다. 디버깅하기 좋은 소스와 코딩하기 좋은 소스는 분명 구별됩니다. 어떤 것이 과연 디버깅하기 좋으냐에 대한 생각은 다를 수 있지만, 아무 소스나 보면서 그 소스에 대한 깔려 있는 생각을 읽을 수 없다면 습관이 잘못 들어 디버깅은 더 어려워질 수 있습니다. 그럴지라도 다른 사람의 소스를 많이 보십시오. 소스포지나 코드구루 등은 공개된 소스를 얻을 수 있는 좋은 사이트입니다. 특히, 팀으로 작업하는 프로젝트의 소스를 보십시오. 그 팀에서 코딩 가이드를 제시하고 있다면 더더욱 소스에 대한 질이 높아집니다.
나중에 다른 API를 사용해 연동할 일이 생긴다면, 그 소스를 볼 수 있다는 것은 디버깅에 큰 도움을 주게 됩니다. 한 페이지의 매뉴얼보다는 한 페이지의 소스가 더 도움이 되는 법이지요. 소스에 대한 경험이 많을수록 소스에서 느끼는 부드러움과 안정감, 위태로움, 불안함에 대한 감각이 자라나게 됩니다. 다른 사람의 소스를 읽는다는 것은 그 사람과 대화하는 것입니다. 그렇게 되면 코딩 스타일이라는 굴레를 벗어나게 되는 것입니다. 감상하는 법을 아는 사람만이 예술 작품세계에 대한 평을 할 수 있는 것입니다. 감상하는 법을 아는 사람이 설계 패턴과 설계 철학을 읽을 수 있습니다. 그리고 자연스럽게 자신의 소스에 대한 섬세한 손질을 할 수 있습니다.

표준 문서 숙지 - 네트워크 프로그래밍 디버깅
네트워크 프로그래밍은 필수 요소로 프로토콜이라는 전송 규약이 수반됩니다. 디버깅의 1차 목표는 프로토콜에서 정의한 패킷들이 필드 규격에 맞게 전송되고 있는지를 확인하는 것입니다. 그리고 다음으로는 필드의 내용이 프로토콜에 맞게 제 값을 가지고 다니는지를 확인하는 것입니다. 이를 위해 수반되는 것은 TCP/IP에 대한 명세를 확실히 하는 것입니다. TCP/IP 기반 네트워크 프로그래밍에서는 필수적으로 MAC 어드레스에 대한 개념과 IP 어드레스, 네트워크 어드레스, 브로드캐스팅 어드레스, 넷마스크, 디폴트 루트에 대한 개념을 책을 보며 익히되 패킷을 캡처해 가면서 공부하는 것을 권합니다. 더미 허브(스위칭 허브가 아닙니다)를 사용하면 네트워크에서 돌아다니는 모든 패킷을 다 읽을 수 있으므로, 패킷 캡쳐 툴을 사용해 가만히 들여다 보는 것만으로 책안의 내용이 살아나게 됩니다. 이런 툴 하나 정도는 꼼꼼히 옵션 찾아가며 익힐 것을 권합니다. tcpdump를 권하며, 윈도우에서는 같은 류의 windump가 있습니다. 둘의 옵션이 비슷하므로 하나를 익히면 다른 것도 쉽게 사용할 수 있습니다. 그 외에 GUI로 제공하는 많은 툴이 있으므로 찾아서 익히기 바랍니다(검색어 packet capture, sniffing).
인터넷 필수 기본 프로토콜에 대한 것은 문서를 익히는 것에서 패킷 캡처를 통한 확인, 그리고 많은 커맨드 라인 방식의 프로토콜(SMTP, HTTP, POP, NNTP, FTP)에 대해서는 telnet을 이용한 테스트까지 완전히 자기 것으로 만들어야 합니다. 물론 샘플을 구해 클라이언트를 만들어 본다면 더 없이 훌륭합니다. 네트워크 프로그래밍 개발자들이여, 문서를 읽어 용어를 아는 정도는 비개발자들도 하는 것입니다. 하물며 개발자는 패킷 캡처까지 하여 프로토콜 확인은 할 줄 알아야 합니다.

깊은 프로그래밍을 위한 첫 발걸음
소스를 많이 보면서 구체적인 점을 이야기하지 않았습니다만, 전반적으로 프로그래밍과 디버깅을 시작하는 사람들이 가져야 할 모습을 다루어 보았습니다. 시작부터 튼튼한 사람은 없습니다. 처음에는 버그를 잡았지만, 소 뒷걸음에 쥐를 잡은 듯이 넘어가는 일이 많습니다. 프로그래밍과 디버깅을 따로 뗄 수는 없는 것입니다. ‘코딩 끝 디버깅 시작’이라는 말같이 디버깅을 염두에 두지 않은 코딩은 그 깊이가 얕을 수밖에 없습니다. 프로그래밍이라는 작업은 만만치 않지만, 설계부터 코딩, 디버깅이 끝난 프로그램이 잘 돌아가는 것을 보는 것은 예술가적인 안목에서 참 흐뭇한 일입니다. 짧은 연재이지만, 뒤 이어지는 연재들을 같이 나누며 깊은 프로그래밍을 위한 발걸음을 차근차근 내딛어 봅시다.

프로그래머는 그 고집만큼 습관이 고착되어 있습니다. 여러 습관 중에서 가장 강조하고 싶은 것은 다음과 같습니다.

◆ 코딩 규칙 준수
◆ 로그 API 먼저 작성하기
◆ Assert문 이용하기
◆ 자원 관리 철학 갖기
◆ 다중 if문 갖지 않기

디버깅에 관한 코딩 습관
코딩 규칙을 준수합시다

개발이 시작되면 대개의 경우 팀으로 프로그래밍을 하게 되며, 설계가 끝나고 코딩에 들어가기 전에 항상 코딩 규칙을 만들게 됩니다. 혹은 회사에 전부터 정해진 코딩 규칙이 있다면 그것을 개발에 적용하게 됩니다. 이런 코딩 규칙은 통일을 기하기 위해 만들어집니다. 파일 명명법, 함수․변수 명명법, 괄호의 위치, 파일 주석, 함수 주석, 선언 주석, 들여쓰기 방법 등에 대한 것을 기술하며, 훈련이 잘 되어 있는 개발팀이라면 이런 코딩 방법에 대한 통일을 이루게 됩니다.

코딩 규칙은 미래의 자신과 개발 중인 다른 사람과의 협업을 위해서는 반드시 지켜야만 하는 것입니다. 이런 코딩 규칙과 디버깅과의 상관 관계는 일부 코딩 규칙이 버그 발생을 예방하기 위해 만드는 것이 있다는 것입니다. 필자가 권하는 것은 컴파일러다운 관용의 자세를 가지라는 것입니다. 이 말은 아무렇게나 작성하라는 것이 아니라 코딩 규칙이 프로젝트가 바뀔 때마다 변할지라도 자신을 능동적으로 맞춰가라는 것입니다. 코딩 규칙 중에서 많은 프로젝트에서 사용하는 두 가지를 소개하겠습니다.

◆ 단일 실행문을 갖는 if, while, for문이라 할지라도 중괄호(‘{’, ‘}’)를 기입한다(<리스트 1>).
<리스트 1>과 같은 규칙은 처음 작성할 때는 문제가 되지 않지만, if 안의 블럭에 실행문을 하나 더 추가할 일이 생길 경우 중괄호가 없는 예에서는 간혹 실수하여 if의 참, 거짓에 상관없이 다음에 실행되는 문장으로 인식될 수 있는 경우가 발생합니다. 특히 printf(“Check %s:%d”, __FILE__, __LINE__);과 같이 중간 중간 현재 진행되는 위치를 출력하려고 중요한 위치(함수 시작, 조건 판단, 함수 종료 등의 위치)에 마구 복사해 넣다 보면 <리스트 1>과 같은 경우가 흔히 발생합니다. 다른 예를 들어 보겠습니다.

<리스트 1> 코딩 규칙 1
규칙 준수 예 :
if( pTemp != NULL ) {
*pTemp = ‘x’;
}

규칙 미준수 예 :
if( pTemp != NULL )
*pTemp = ‘x’;


◆ ++, -- 연산자는 함수 호출 인자 내에 쓰지 않고 호출 앞 혹은 뒤에 따로 쓴다(<리스트 2>).
-- 위치에 따라 ‘사용 후 감소’ 또는 ‘감소 후 사용’이라는 모호성과 함수 호출시 인자로 넘어갈 값을 결정하는 순서(<리스트 2>에서는 두 번째 인자 --count와 세 번째 인자 score[count])가 섞이면 상당히 골치 아픈 일이 발생합니다. <리스트 2>에서는 count가 printf에 넘어간 뒤 --가 수행될지, --가 먼저 되고 printf에 넘어갈 지에 대해 생각을 합니다. 또한 printf 함수에 넣기 위해 --count를 먼저 할지, score[count]를 먼저 계산할 지에 따라 score 배열의 인덱스가 달라지는 문제가 발생합니다. --에 대한 것은 책을 찾아 명확하다고 할지라도 함수에 넘길 인자의 정확한 값을 구하기 위한 순서는 컴파일러마다 다를 수 있습니다. 모든 컴파일러가 같다고 할지라도 가독성을 떨어뜨리므로 좋은 코딩이라고 볼 수 없습니다.

<리스트 2> 코딩 규칙 2
--count;
printf( “Last index %d, Last value: %d”, count, score[count] );

규칙 미준수 예 :
printf( “Last Index: %d, Last value: %d”, --count, score[count] );

간단히 코딩 규칙의 예 중에서 버그 방지를 위한 것들로 자주 사용되는 것을 살펴봤습니다. 디버깅과 상관없이 코딩 규칙에 대해 말하자면, 코딩 규칙을 따르지 않고 자신만의 습관을 사용하는 것은 프로다운 모습이 아닙니다. 오히려 전문가는 프로그램 설계, 즉 구조에 중점을 두어야 합니다. 자신만의 코딩 규칙보다는 팀의 규칙을 따르는 것이 도움을 주고받을 때에도 시간을 단축할 수 있습니다. 필자가 속한 그룹에서는 들여쓰기와 괄호 위치, 선언 위치 등에 대한 것을 정해 놓고, code beautifier(GNU indent)를 사용하여 표준을 따르도록 고쳐주는 옵션을 정한 뒤 팀원들이 공유하여 코딩 규칙 일부에 대해 자동화합니다.

Log API 만들기
사실 printf를 디버거라고 부르기에는 적당하지 않습니다. 디버깅을 위한 값을 추적하는 방법에 불과하기 때문이지요. 여기서는 printf로 대표되는 ‘실행 중 값 출력’에 대해 말하고자 합니다. 프로그램을 시작하는 모든 사람이 오류가 발생하면 관심 있는 변수의 추이를 보고 싶어하고, 그런 변수가 실행 중 어떻게 변하는지를 살펴보는 것으로 처음 디버깅을 경험하게 됩니다. 이 방법이 정형화된 것이 바로 다단계 로그입니다. 잘 되어 있는 프로그램은 로그의 단계를 조절할 수 있는 기능(최소한 남길지 말지에 대한 기능)이 있어서 사용자가 종류별, 단계별로 로그를 원하는 파일에 심지어 원하는 포맷으로 남길 수 있습니다. 프로그래밍을 할 때 처음 구현을 위해 남기는 로그를 printf로 남기다가 나중에는 모조리 지웁니다. 왜냐하면 주로 이런 모습이기 때문입니다.

!!!! temp file name: gHie88009.dat
-------------- CHECK 1
---------------CHECK 2
client: 192.168.10.1 2890 8 17:30:13

아무 의미 없어 보이지만 실제 구현되기 전까지 만든 사람에게는 중요한 정보가 됩니다. 구현되고 나면 당연히 주석 처리가 되거나 삭제되는 코드입니다. 체계적인 로그 관리는 참으로 중요합니다. 나중에 문제가 생길 경우, 심지어 고객에게 배포된 것에 문제가 생길 경우에는 로그를 보내주고, 그 로그를 받아오면 좋은 경우가 많기 때문입니다. 앞과 같은 로그를 남기는 데 그냥 줄 수 있습니까? 애만 태우게 됩니다. 앞과 같은 로그 대신 프로젝트가 사용할 로그 API를 이용합니다. 이때 최상위 레벨, 즉 가장 자세한 상황으로 로그를 남기는 옵션일 때만 남기도록 함수를 하나 만들어 앞 로그를 보기 좋게 수정하여 코드에 넣는다면, 나중에 로그를 자세히 남길 필요가 있을 때(팀장의 협박하에 또는 고객지원을 위해)에도 많은 수고를 덜 수 있게 됩니다.
윈도우 프로그래머들은 TRACE와 TRACEn(n은 string을 제외한 인자의 개수)으로 대표되는 디버그 모드 추적기가 있습니다. 이 경우에 있어서도 될 수 있으면 팀에서 로그 포맷을 정하고, 개발 후에도 삭제하지 않고 유용한 정보로 사용하는 것이 좋습니다.

시공 감리 assert
‘assert를 잘 쓰면 기본은 뗐다’고 칭찬해 줄 정도입니다. 잘 쓴다는 얘기는 남발한다는 것이 아니라 필요한 부분에는 꼭 쓰고, 쓰지 말아야 할 곳에는 안 쓴 코드를 말합니다. assert는 중요하지만 많은 실전 경험 없이는 기술이 완성되는 것이 아니므로 몇 가지 예를 들어 설명하겠습니다. assert 사용이야말로 버그를 줄일 수 있는 가장 중요한 습관입니다. assert는 #include 과 같은 헤더를 포함해야 쓸 수 있습니다. 사용 방법은 단지 assert( <평가식> );과 같은데, 함수 호출이 있으면 <평가식>은 0이 아닌 값, 즉 참 값을 가져야만 합니다.

/* #define NDEBUG */
#include

#include

int main()
{
int i = 0;
assert( i );
}

앞과 같은 코드는 반드시 assert문에서 오류를 발생시킵니다. 오류에는 파일 이름과 행, 그리고 어떤 값이 오류를 일으켰는지에 대한 정보를 보여주게 됩니다. 다시 앞 코드를 컴파일할 때 #define NDEBUG의 주석을 푼 뒤 실행하면 오류가 나지 않음을 알 수 있습求? NDEBUG라는 매크로가 선언되어 있으면 모든 assert문은 빈 명령어가 되는 것입니다. assert.h는 ANSI C 표준에 들어 있으므로 ANSI C를 지원하는 라이브러리가 있다면 어떤 플랫폼에서도 사용할 수 있을 것입니다.

◆ assert는 내부 설계에 대하여 변수가 원하는 내용을 가지고 있는지 확인하는 데 사용한다(<리스트 3>).
<리스트 3>을 보면 두 함수가 등장하는데, process 함수를 SMTP의 ‘서버 메시지 같은 꼴’의 응답 메시지를 처리하는 데 사용하는 함수라 생각해 봅시다. SMTP 결과 메시지의 간단한 모양은 다음과 같습니다.

220 mail.test.com ESMTP Ready

<리스트 3> SMTP 적용 예제
const char szLastMessage[1024];
void saveLastMessage ( const char * szMessage )
{
strncpy( szLastMessage, szMessage, sizeof( szLastMessage ) );
/* sizeof는 배열 szLastMessage의 최대 크기 */
}

/* szLine은 <세 자리 숫자><공백><서버 메시지> */
void process( const char * szLine )
{
int code;
code = atoi( szLine );
saveLastMessage( szLine + 4 );
/* 이하 생략 */
}

SMTP에서는 세 자리의 응답 코드만 가지고 대부분 처리되지만, 사람이 읽을 수 있는 메시지는 한 칸의 공백을 두고 쓰게 되어 있습니다. 이 정도 규약이 있다고 가정합니다. process 함수는 내부에 saveLastMessage 함수를 부르고 있으며, saveLastMessage는 그 인자인 szMessage를 서버의 응답을 처리하는 데 맨 앞에 있는 함수가 아니라는 것을 알고 있습니다. 즉, saveLastMessage는 process라는 선처리 함수 뒤에서 작용하는 함수라는 설계가 반영된 것입니다. saveLastMessage는 적법한 메시지일 경우에 불리운다고 가정합니다. 이런 상황을 두고 적당한 assert 위치와 assert 내용을 살펴봅니다. 일단 함수에 들어오는 szLine, szMessage에 대한 상황을 생각해 봅니다.

saveLastMessage :
ꊱ szMessage는 널 포인터가 아니어야 한다.
ꊲ szMessage는 실제 내용이 있어야 한다.

process :
ꊱ szLine은 널 포인터가 아니어야 한다.
ꊲ szLine[0], szLine[1], szLine[2]는 숫자이어야 한다.
ꊳ szLine[3]은 공백이어야 한다.
ꊴ szLine + 4 위치에 메시지가 들어 있어야 한다.

<리스트 4> assert의 적용 예
const char szLastMessage[1024];
void saveLastMessage ( const char * szMessage )
{
assert( szMessage ); /* null pointer가 아님 */
assert( szMessage[0] ); /* 실제 내용이 있음 */
strncpy( szLastMessage, szMessage, sizeof( szLastMessage ) );
/* sizeof는 배열 szLastMessage의 최대 크기 */
}

/* szLine은 <세 자리 숫자><공백><서버 메시지> */
void process( const char * szLine )
{
int code;
assert( szLine ); /* null pointer 아님 */
assert( isdigit(szLine[0]) && isdigit(szLine[1]) && isdigit(szLine[2]) ); /* 세 자리 숫자 */
assert( szLine[3] == ‘ ’ ); /* 공백 */
assert( szLine[4] ); /* 실제 메시지 내용 있음 */
code = atoi( szLine );
saveLastMessage( szLine + 4 );
/* 이하 생략 */
}

앞과 같은 사항을 반영한 assert가 들어간 코드는 <리스트 4>와 같습니다. assert와 관련해 szLine과 szMessage의 가장 큰 차이는 설계상 szLine은 처음으로 서버 즉 외부의 데이터를 받는 부분이고, szMessage는 한번 걸러진 변수라는 것입니다. szLine이 준수해야 하는 규칙은 서버에서 응답을 이상하게 준다면 충분히 깨질 수 있는 상황이며, 그런 상황이 벌어진다면 saveLastMessage는 적법한 경우가 아니므로 불리우지 않는 것이 설계의 내용입니다. 그러므로 적법한 상황에서 불리우는 szMessage는 알 수 없는 오류가 있지 않는 한 널 포인터일리 없고 내용이 없을리도 없습니다. 따라서 설계상 서버의 오작동과 같이 외부 입력에 대한 것을 처리할 수 있는 것은 assert로 하는 것이 아니라 if문으로 처리하여 적절한 오류 처리 루틴을 따라야 합니다. 외부 데이터의 변화와 상관없는 assert를 정리하면 다음과 같습니다.

saveLastMessage :
ꊱ szMessage는 널 포인터가 아니어야 한다.
ꊲ szMessage는 실제 내용이 있어야 한다(szMessage 길이가 0으로 saveLastMessage 함수가 호출되지는 않는다).

process :
ꊱ szLine은 널 포인터가 아니어야 한다.
ꊲ szLine에 코드를 비롯한 메시지가 들어 있어야 한다(szLine 길이가 0으로 process 함수가 호출되지는 않는다).

<리스트 5> 설계와 구현에 대한 assert의 용법
void process( const char * szLine )
{
int code;
assert( szLine ); /* null pointer 아님 */
assert( szLine[0] );
/* 서버의 응답의 적합성을 파악하기 위해서는 길이가 적어도 4바이트가 되어야
배열 참조 인덱스가 유효하므로 먼저 길이 조사를 한다. */
if( strlen( szLine ) < 5 ||
! (isdigit(szLine[0]) && isdigit(szLine[1]) && isdigit(szLine[2]) ) ||
szLine[3] != ' ' )
{
/* 오류 로그 */
return;
}
code = atoi( szLine );
saveLastMessage( szLine + 4 );
/* 이하 생략 */
}

<리스트 5>는 설계와 구현에 대한 assert의 용법에 대해 알아 본 것입니다. 함수의 모든 인자에 대한 것은 함수 첫 부분에서 assert를 해줘야 합니다. 클래스 멤버 함수에 관해서는 인자뿐 아니라 사용하는 멤버 변수에 대한 것도 포함됩니다. 다음은 대표적인 assert문이 사용되는 방법입니다.

ꊱ 포인터의 경우 널인지 여부
ꊲ 일반 변수의 설계상의 범위 혹은 정확한 값 준수 여부
ꊳ 다중 if, else if, switch 등의 복잡한 판단 후 처리에 대한 결과 확인



assert를 사용하지 말아야 할 대표적인 곳은 다음과 같습니다.

ꊱ 외부 데이터 입력 변수
ꊲ 메모리 할당 결과
ꊳ 파일 열기 결과

이번에는 assert를 프로그래밍 습관보다는 디버깅에 사용하는 방법을 생각해 봅시다. 디버깅할 때 심지어는 멤버 함수의 경우 this 포인터가 널이 아닌지 확인해야 하는 경우도 있습니다. 버그가 발견되었을 때 문제가 발생한 곳을 중심으로 의심가는 곳에 assert를 심어 넣습니다. 이 경우에는 assert가 오류를 내고 프로그램이 멈추어야 되므로, 앞에서 사용하지 말아야 할 상황까지 일부러 넣어가면서 프로그램을 임시로 지저분하게 가져가야 합니다. 사용하지 말아야 할 곳에 넣은 assert는 나중에 다시 빼야 하므로 아예 들여쓰기를 하지 않고 넣는 것도 한 방법일 것입니다. 이 방법은 if로 조건을 벗어나는 것에 대한 로그를 남기는 것보다 확실합니다.
정리하면 assert는 설계의 흐름을 제대로 구현하고 있는가에 대한 감리 역할을 하고 있는 것입니다. 많은 경우 아주 가끔씩 일어나는 에러의 경우에도 assert를 충분히 해주었다면 쉽게 잡을 수 있는 경우가 있습니다.

자원 미제거에 대한 방어
자원 할당 또는 제거라 함은 메모리 할당, 파일 open, socket accept, close 등을 말합니다. 시스템 자원(메모리 포함)의 새는 것(resource leakage)에 대한 추적은 디버깅의 어떤 언어든 끝없는 주제일 것입니다. 메모리 및 시스템 자원에 대한 것은 다음과 같은 설계 철학을 공유하지 않으면 체계적이 될 수 없습니다. 물론 메모리 새는 것과 자원 새는 것들에 대해 추적할 수 있는 도구 혹은 추적 가능하게 해주는 라이브러리를 사용하는 방법이 있습니다만, 소스 수준에서 올바를 습관을 기르면 디버깅에 도움이 될 수 있기에 정리해 봅니다.

ꊱ 자원 할당과 제거를 동일한 계층에서 일어나도록 한다.
ꊲ 자원 할당과 제거를 논리적으로 시작 모듈과 끝 모듈에 맞추어 일어나도록 한다.

둘은 서로 반대되는 얘기입니다만 일종의 패턴이라고 생각하면 됩니다. 첫 번째, 자원 할당과 제거가 동일한 계층에서 일어난다는 것은 같은 모듈 내에 생성 소멸을 두라는 이야기입니다. 다른 말로 하면, 가능하면 자원을 할당한 함수에서 해제하라는 것입니다. 또는 그것이 불가능할 경우 같은 클래스 안에서 혹은 동일한 파일 내에서 할당, 제거할 수 있는 설계 방법을 취하는 것입니다. 두 번째는 생성되는 곳과 소멸되는 곳을 특정한 두 개 정도의 함수, 클래스 혹은 파일로 모으라는 것입니다. 만약 쓰레드 등을 써서 소켓을 accept하는 곳과 close하는 곳이 분리돼야만 한다면, 여러 곳에서 close하지 말고 모아두라는 것입니다. 즉, 프로세스의 시작과 끝이 다른 경우에는 자원이 생성되고 소멸되는 위치가 되도록 모여 있도록 하라는 것입니다.

이런 패턴을 따르지 않을 경우 할당 제거에 대한 명확한 문서화가 되어 있어야 합니다. 되도록 그런 문서를 만들지 않아도 알기 쉽게 앞 패턴을 따르는 것이 좋습니다. 다음은 같은 함수 내에서 제거하는 모습입니다. 나쁜 예는 process 함수 내의 주석 처리한 부분에서 pConfig 객체가 소멸되는 것입니다.

void process( Config * pConfig )
{
/*... 처리 ... */
/* delete pConfig; */
}

void run()
{
Config * pConfig = new Config("/etc/test.cfg"); /* pConfig가 널인지 확인하는 코드 생략 */
process( pConfig );
delete pConfig;
}

◆ 자원 할당 전에 변수가 비어 있는지 확인해야 한다.
◆ 자원 제거 후에는 변수를 초기 값으로 환원시켜야 한다.

자원 할당 전에 할당한 자원을 받을 변수에 어떤 의미있는 내용이 있는지 확인해야 합니다. 또한 자원 제거 후에는 반드시 그 변수를 초기 값으로 환원시켜서 다음에 해제되었는지를 확실히 해야 합니다.

/* 메모리 할당, 해제 전에 확인 */
if( pBuffer )
{
free( pBuffer );
}
pBuffer = (char *) malloc( BUFFER_SIZE );
/* 처리 */
if( pBuffer )
{
free( pBuffer );
pBuffer = NULL;
}

/* 파일 닫은 후에 초기화 */
if( fd >= 0 )
{
close( fd );
fd = -1;
}

좀더 상세하게 살펴봅시다. 다음의 예에서 g_pBuffer와 fd 변수는 초기 값으로 각각 NULL, -1을 가지고 있다고 합시다.

/* --- MEMORY --- */
if( !g_pBuffer ) {
g_pBuffer = (char &) malloc( BUFFER_SIZE );
}
/* --- FILE --- */
if( fd >= 0 ) {
if( !close(fd) ) {
printf(“close error”);
}
}
fd = open( “/tmp/log.txt”, O_RDONLY );

이제 자원 할당 문제와 assert를 이용한 디버깅을 알아봅시다. 앞의 예에서 g_pBuffer 값이 논리적으로 프로그램 흐름상 g_pBuffer는 초기화되어 있어야 한다면, 또한 open하기 전에 fd 값이 초기 값(-1)을 유지할 수밖에 없다는 것이 확실하다면, 즉 모든 실행 경로에서 if 조건들이 결코 참이 될 수 없다면 if 위에 assert를 넣어 다음과 같이 만들어 자신의 논리를 굳히는 프로그래밍을 할 수 있어야 합니다. 문법 오류를 컴파일러가 잡아내듯 논리 오류를 잡아내는 데 사용됩니다. 실행 도중 논리적인 설계 외의 행위가 발생한다면 그것은 디버깅감입니다.

assert( g_pBuffer );
assert( fd < 0 );

◆ 불필요하게 파일 기술자를 두 번 이상 close하지 않는다.
뭔가 확실히 해두려고 두 번 이상 파일 기술자를 닫는 경우가 있습니다. 이 경우 두 번째의 close는 당연히 닫힌 파일에 대한 close이므로 오류를 일으키며, 일반적으로 프로그래머는 close의 오류 확인을 하지 않는 경우가 많습니다. 물론 앞의 습관이 제대로 들어 close 후에 -1(혹은 Handle의 경우 NULL)로 초기화하고, close할 때는 반드시 0보다 크거나 같은지에 대해 확인을 하겠지만 그것은 안전을 위한 방법이며, 그것보다 먼저 점검할 것은 생각할 수 있는 모든 경로에서 정확히 close를 한번만 하는지 확인하는 것입니다. close 전에 assert를 넣어 두 번 close를 하는지 점검해 보는 것도 좋습니다.

다중 if문 피하기
다중 if를 최대한 줄일 수 있도록 만들면 그만큼 가독성을 높게 합니다. <리스트 5>와 <리스트 6>을 비교하면 처음 만나는 if문을 바꿔 씀으로써 이중 if문을 단일 if로 바꾸었습니다. <리스트 5>와 같은 코드는 나름대로 정상적인 흐름을 머릿속에 생각하고 정상적인 것만 처리하는 데 집중하여 나온 것입니다. 습관을 바꾸면 비정상적인 것을 먼저 판단하되 비정상적인 것이 잘 일어나지 않는 상황입니다.

게다가 로그를 남겨야 하는 등 많은 일을 처리해야 한다면 assert문을 넣어 그 함수 안에 들어오면 반드시 오류가 나도록 처리해 두고, 그 아래에 계속 생각의 흐름을 진행시키는 방향으로 코드를 작성하는 것이 좋습니다. 이런 습관은 일석이조의 효과를 거두게 됩니다. 코드의 가독성을 높이고, 구현을 미루어 놓아도 나중에 까먹지 않게 되지요. 다음과 같은 방법으로 간단히 처리하고 나중에 assert에 걸릴 때 적절한 코드를 넣어도 정상적인 것을 우선 작성하는 데 큰 어려움이 없을 것입니다.

if( 0 >= (size=recv( s, buf, 1024, 0 )) ) {
assert( 0 && “TODO: You should process error”);
}

<리스트 5> if문 사용 예 1
int check( s )
{
char buf[1024];
int size = 0;
if( 0 < (size=recv( s, buf, 1024, 0 )) ) {
buf[size] = ‘\0’;
if( ‘2’ == buf[0] ) {
return 0;
}
return 1;
}
printf(“Socket closed.”);
return -1;
}

<리스트 6> if문 사용 예 2
int check( s )
{
char buf[1024];
int size = 0;
if( 0 >= (size=recv( s, buf, 1024, 0 )) ) {
printf(“Socket closed.”);
return -1;
}
buf[size] = ‘\0’;
if( '2' == buf[0] ) {
return 0;
}
return 1;
}

빌드 과정 파악하기
지난 호에서 필자는 ‘언어와 환경’이라는 주제로 언어 명세와 라이브러리를 분리할 줄 알아야 한다고 했습니다. 이번에는 언어와 라이브러리를 조작하는, 흔히 말하는 컴파일러를 분석해 보겠습니다. 범용성을 가진 언어로서 C/C++는 그만큼 많은 제작사가 있으며, 많은 컴파일러를 만들어 내놓았습니다. 그 중에는 상용도 있으며(비주얼 C++, 볼랜드 C++ 빌더, 솔라리스 cc 등), 상용에 못지 않은 공개용(gcc/g++, djgpp, mingw)도 있고, 상용이었다가 이제는 공개용(터보 C)으로 된 것도 있습니다. 이들은 일부는 순수한 컴파일러만을 가지고 있으며, 일부는 어셈블러와 링커까지 포함된 것도 있습니다. 또 어떤 것은 통합 환경을 제시하는 것도 있고, 어떤 것은 커맨드라인 실행만을 지원합니다.

이런 구분을 잘 이해하려면 어떤 언어든지 다음을 이해해야 합니다. 디버깅이 어려운 것은 이런 구분 없이 오류를 해결하려고 하기 때문입니다. 한 번의 빌드 중에는 다음과 같은 일이 발생합니다. 간단한 명령 하나를 내리는 것 같지만 소스는 전처리 과정을 거쳐 컴파일러에 들어가고, 컴파일되어 나온 어셈블 코드 혹은 메타 언어 코드는 어셈블러를 통해 목적 파일이 생기고, 여러 목적 파일들을 합하여 하나의 실행 파일을 만들게 됩니다. 이 과정에서 중간에 에러 메시지가 나오게 됩니다. 그 에러 메시지가 다음 중 어떤 과정에서 일어나는지를 이해하는 것이 디버깅을 돕는 빠른 길입니다.

ꊱ 전처리기(pre-processor)
ꊲ 컴파일러(compiler)
ꊳ 어셈블러(assembler)
ꊴ 링커(linker)

이런 구분을 몇 가지 에러 메시지를 통해 이해해 봅시다. 전처리기와 링커의 경우를 살펴보겠습니다. 처음에는 숨겨 있기 때문에 바로 알 수 없는 경우가 많거든요.



<그림 1> 빌드 순서 개요




전처리기
전처리기, 즉 컴파일러에 들어가기 전에 처리하는 대표적인 것은 다음과 같습니다.

ꊱ #ifdef/#else
ꊲ #define
ꊳ #include

컴파일러는 사실 앞의 구문을 이해하지 못합니다. 앞의 내용을 바탕으로 컴파일러에 소스 중 일부만을 넘긴다거나 치환하여 넘긴다거나 다른 소스를 포함시켜 넘기는 것입니다. 컴파일러가 보는 것은 앞에서 제외한 모든 것이라 보면 되겠습니다. 그 중 유의할 것은 ꊱ typedef, ꊲ #pragma이지요. typdef와 #define을 많이 비교하는데, 사실은 처리하는 위치가 다르다는 것을 기억해 두기 바랍니다. pragma는 표준화된 것이 아니므로 컴파일러마다 다르다는 것을 이해해야 합니다. 따라서 컴파일러마다 공통적인 것이 아니라면 #pragma 앞뒤로 컴파일러 특유의 매크로가 정의되었는지 확인하는 #ifdef가 오게 됩니다. 다음은 C++ 코드입니다.

/* filename: a.cpp */
int main()
{
printf("Hello, world\n");
return 0;
}

앞의 코드를 컴파일하면 제대로 되지 않습니다. “implicit declaration of function ‘int printf(...)’”라는 오류를 내면서 멈추게 됩니다. printf를 암묵적으로 선언하여 사용했기 때문이죠. 즉, 정확한 선언 없이 사용했다는 것입니다. 이것이 C라면 암묵적인 선언도 무사하겠지만, C++라면 반드시 선언해야만 함수를 사용할 수 있으므로 컴파일이 더 이상 진행되지 않습니다. 선언을 제대로 하는 것은 어떻게 보면 컴파일러 문제겠지만, 우리는 여기에서 #include 라는 헤더 파일이 빠져 있음을 알 수 있습니다. stdio.h를 열어 보면, 어딘가 printf 함수의 원형이 선언되어 있음을 알 수 있을 것입니다. 이것은 전처리되어 앞에서 헤더가 포함되어 함수를 선언해 주는 것이 빠져 있기 때문에 생긴 것입니다. 물론 #include하지 않고 해당 printf를 앞에 그대로 복사해 놓아도 상관없습니다. 그것은 전처리기를 통하지 않고 컴파일러 안에서 처리한 것이죠.


전처리의 특성 파악
전처리의 특성을 알면 유용할 때가 많습니다. 컴파일 옵션 중에 미리 선언한 값을 넘기는 경우가 있습니다. 그 값에 따라 #ifdef를 만나면 소스의 특정 부분을 선택적으로 컴파일할 수 있게 되지요. 디버깅을 하다 보면, 헤더 파일을 열었을 때 두 가지 선택 중 어떤 것이 선택되었을까 궁금할 때가 있게 됩니다. 이런 경우를 대비해서라도 컴파일 전에 들어가는, 즉 전처리된 소스를 한번 보기로 합시다.
앞 코드를 #include 를 넣어 제대로 돌아가도록 한 뒤 전처리기만 통과하여 나온 소스를 보기로 합시다. 유닉스용 g++의 경우 -E 옵션을 넣어 주면(g++ -E a.cpp) 컴파일러에 들어가기 전의 코드를 구할 수 있습니다.

비주얼 C++ 6.0의 경우 도스 명령 창을 실행하여 해당 소스가 있는 곳으로 이동한 뒤 cl /E a.cpp라고 명령을 내려주면 됩니다. cl 명령이 실행되지 않을 경우 경로가 잡혀 있지 않기 때문입니다. cl은 Visual Studio\VC98\Bin 디렉토리에 있습니다. cl이 바로 gcc/g++과 같은 역할을 하는 컴파일러인 것이지요. 정확히 cl과 gcc/g++ 등은 컴파일러를 부르는 구동기입니다.

링커
링커는 컴파일되어 나온 목적 파일들을 서로 묶어 주는 역할을 하는 것입니다. 흔히 이런 오류를 많이 보게 됩니다. 다음은 앞의 소스에서 main을 test로 이름을 바꾼 것입니다. 즉, 전체 프로젝트에 main 함수가 없는 상황이죠.

<리스트 7> a.cpp
#include
int test()
{
printf("h");
return 0;
}

g++ a.cpp -o a
/usr/lib/crt1.o: In function ‘_start’:
/usr/lib/crt1.o(.text+0x18): undefined reference to ‘main’
collect2: ld returned 1 exit status

VC++
Compiling...
a.cpp
Linking...
LIBCD.lib(crt0.obj) : error LNK2001: unresolved external symbol _main
Debug/a.exe : fatal error LNK1120: 1 unresolved externals
Error executing link.exe.

<리스트 7>을 보면 컴파일러가 다름에도 불구하고 undefined reference, undefined external symbol이라는 비슷한 오류가 발생했습니다. 그리고 g++에서는 crt1.o, VC에서는 crt0.obj이라는 것을 보게 됩니다. 마지막으로 g++에서는 collect2(ld)가, VC에서는 link.exe가 오류를 내는 것을 확인할 수 있습니다. 흔히 처음 이런 오류를 만났을 때에는 고민하다가 main 함수가 없어서 발생하는 것을 알게 되지요. 좀더 살펴보면 오류를 낸 것은 링커입니다.

오류의 위치는 main이라는 reference 혹은 external symbol을 찾지 못했다는 것이고 공교롭게도 crt 뭔가를 처리하다가 발생했습니다. 즉, 컴파일은 모두 성공적으로 끝났으며, 그 다음 단계인 링킹에서 오류가 발생한 것이지요. VC의 경우 main 대신 _main을 찾다가 생긴 오류로 나오는데 이것은 윈도우에서 흔히 사용하는 오브젝트 내의 심볼 표현 방법으로 C언어에서 만든 함수 이름 앞에 “_”을 붙이기 때문입니다. 메시지의 정확한 의미는 C++ 컴파일러가 crt라는 런타임 오브젝트를 먼저 처리하며, 그 오브젝트 안에는 다른 프로그램 어딘가로부터 main 함수를 필요하도록 만들어져 있습니다. 따라서 그것을 연결시켜야 하는데 전체 프로젝트 안에 main이라는 오브제트가 없는데서 발생한 것입니다.

비슷한 오류는 특정 라이브러리를 추가로 넣어줘야 하는데 빠졌을 경우 발생합니다. 윈도우 프로그램을 작성할 때는 소켓 라이브러리를 따로 프로젝트 환경 설정에 넣어야 하는 경우가 있고, 유닉스의 경우에도 수학 관련 함수를 사용할 때나 쓰레드 관련 프로그램을 할 때 항상 추가적인 라이브러리를 지시해 주어야 하는 경우가 있습니다. 모두 undefined reference, undefined external symbol 오류입니다. 이것은 컴파일러(어셈블러 포함)를 통과한 소스가 최종적으로 생성되어 나온 오브젝트는 내부에 포함된 함수와 외부로부터 필요한 함수가 어딘가에 기록되어 있다는 뜻입니다. 물론 변수도 그와 비슷하게 기록되어 있습니다. 이런 것을 알아보는 것이 부속 프로그램으로 따라 다니게 됩니다.

디버깅을 잘하는 것에 대하여 지난 호에 덧붙이자면, 언어와 환경(라이브러리, OS, 프로토콜)을 구별할 줄 알아야하며, 현재 오류가 난 부분이 전처리에서 난 것인지 컴파일에서 난 것인지 링커에서 난 것인지 구별할 줄 알아야합니다.

빌드 과정 정리
전처리기를 통하여 나온 소스는 모든 변수와 함수는 사용 전에 선언되어 있어야 하며, 컴파일러 명세에 있는 문법구문이 아닌 것은 모두 typedef되어야 합니다. 따라서 전처리를 통과하여 나온 것에는 주석이 모두 제거되고, 모든 #define문이 치환되며, include된 것들은 통째로 하나의 파일로 되어 전달됩니다. 이 소스를 볼 수 있다면 여러분이 소스를 깊게 이해하고, 디버깅하는 데 도움이 될 것입니다.
컴파일러를 통해 나온(정확히는 컴파일러와 어셈블러를 거쳐 나온) 목적 파일은 C 런타임 라이브러리(crt)와 결합하여 실행 파일을 만들게 됩니다. 따라서 모든 목적 파일과 crt에는 undefined symbol된 것이 어딘가에는 존재해야만 합니다. 만일 존재하지 않는다면 그것은 DLL(혹은 유닉스의 .so, .sl 등)과 같은 동적 연결 라이브러리 파일명을 적어 두고, 로더에 의해 실행 도중에 바인드되도록 만들어집니다.

진정한 전문가의 자세
지금까지의 설명을 토대로 생각하면 디버깅 과정은 빌드 과정을 깊이 이해하는 것처럼 보입니다. 사실 디버깅은 빌드 과정에 대한 이해는 기본으로 하고, 빌드 이후에 있는 어셈블리어를 통한 디버깅이나 System call trace를 통한 프로그램의 흐름을 상상하며 문제의 위치를 찾아내는 것을 주로 지칭합니다. 중요한 것은 시행착오를 남길 때마다 표면적인 문제가 해결된 것에 만족하지 않고, 내부 동작을 좀더 음미해가면서 문제를 해결하려는 태도입니다.

따라서 디버깅은 고도의 좋은 의미의 해킹과도 관계 있는 것입니다. 더불어 좋은 코딩 습관은 고집스런 뭔가를 고수하는 것보다 보다 유연하게 팀 작업을 돕기 위한 모습으로 자신의 활동 범위를 넓히는 것이 좋습니다. 진정한 전문가는 코딩 스타일보다 아키텍처에 관한 얘기를 하는 것입니다. 아무쪼록 깊은 이해를 위해 좋은 습관과 컴파일러와 그 주위를 둘러싼 유틸리티와 친해지길 바라며, 세부 옵션도 수시로 확인하고 정교하게 도구들을 사용할 수 있는 여러분이 되길 바랍니다.

어떻게 하면 버그를 빨리 발견할 수 있을 것인가? 이것은 모든 프로그래머의 공통적인 관심사입니다. 많은 언어들은 이것에 부응하기 위해서 문법적인 장치들을 고안해 넣었습니다. 문법에 그런 장치를 넣었다는 것은 컴파일러에 의해 사용자의 의도 중에 잘못될 소지가 있는 것을 지적할 수 있는 이점이 있습니다. C/C++가 어려운 이유는 변수 타입이 다양하며, 심지어 각 타입에 signed/unsigned가 추가되고, 포인터에는 const이냐 아니냐에 따라 생각해야 할 많은 성질들이 들어가기 때문입니다. 현존하는 언어 중에서 변수에 대한 가장 섬세(?)한 조절 기능이 있다고 해도 과언이 아닙니다. 어쨌든 버그를 컴파일 타임으로 끌어 올려 발견할 수 있도록 하는 것이 문법이 가지는 목적 중 하나이며, 그런 문법의 의도를 충분히 이해하고 언어를 사용할 수 있다면 컴파일러가 단순히 컴파일만을 목적으로 하는 것이 아니라 디버깅 툴(?)로도 사용될 수 있음을 알 수 있습니다. 세 가지 예를 들어 프로그래밍의 깊이를 조금 깊게 느껴보는 시간을 갖기로 하겠습니다.

의도를 나타내는 ‘const’
함수는 부르는 자와 불리는 자의 주고받는 행위입니다. 뭘 주고 뭘 받을지에 대한 것을 프로그래머가 의도한 대로 반영하게 되는데, 몇 가지 함수 call을 살펴보면서 이해해 봅시다.

// 함수 선언과 포인터의 의미
1 int strlen( const char * str );
- str이 가리키는 내용을 건드리지 말라.
2 void strncpy( char * buf, const char * source, int max );
- source가 가리키는 내용을 건드리지 말라, buf가 가리키는 내용은 바꾸어도 좋다.
3 int strcmp( const char * s1, const char * s2 );
- s1, s2가 가리키는 것을 건드리지 말라.
4 FILE * fopen( const char * filename, const char * mode );
- fopen에서 넘어 오는 포인터가 가리키는 것을 맘대로 바꾸어도 좋다.
5 int fclose( FILE * fstr );
- fstr가 가리키는 내용은 바꾸어도 좋다.

앞에 잘 알려진 표준 C 라이브러리의 문자열 처리와 파일 개폐 함수를 나열하였습니다. 선언된 내용 중 포인터에 대한 것을 말로 서술하여 표현해 보았는데, 자세히 읽어보고 원래 함수가 하는 일과 비교하여 이해하기 바랍니다. const가 꾸미는 내용은 변수가 아니라 변수가 가리키는 것의 속성입니다.

// const 선언의 예
6 const char * buf;
7 char const * buf;
8 char * const buf;
9 const char * const buf; 또는 char const * const buf;

1번의 의미는 “ *buf = ‘a’; ”와 같은 방법으로 가리키는 내용을 바꾸는 일로는 사용될 수 없다는 것입니다. 2번의 의미는 정확히 1번과 같습니다. 그것은 const가 “*” 앞에 있어 “*”를 수식하는 것이며, 변수가 가리키는 내용이 상수라는 것입니다.
3번의 의미는 1, 2번과 다릅니다. 즉 가리키는 내용을 바꾸는, “ *buf = ‘a’; ”는 허용되지만 “ buf++ ” 같이 포인터 값 자체를 바꾸는 것은 허용되지 않습니다. 4번의 예는 앞 두 제약을 모두 가지고 있는 것이 됩니다. 이런 생각을 염두에 두고 앞 코드의 1번 문자열 길이를 구하는 함수 strlen이 내부적으로 할 수 있는 예를 생각해 봅시다. 그것은 포인터가 가리키는 값, *str 값이 ‘\0’인지 비교하면서 str++를 수행하며 원하는 결과를 구하게 될 것입니다.
함수를 호출할 때 변수의 포인터를 원하는 함수가 있다고 가정합시다. 만약 그 함수가 const 포인터(const *)를 원한다면 호출 이후 그 내용이 전혀 변하지 않을 것이 확실합니다. 하지만 일반 포인터를 인자로 원한다면 설사 그 함수가 내용을 고치지 않는다고 문서에 씌어 있어도 사실상 보장할 수 없게 됩니다. 이것이 “프로그래머의 의도”입니다. 변하느냐 변하지 않느냐, API 상에 데이터 변형에 대한 의도를 나타내어 버그가 생길 수 있는 소지를 막는 것이 컴파일러가 디버깅을 도와 줄 수 있는 방법입니다. 다음은 const가 있어야 함에도 뺀 함수에 대해 컴파일러는 다음과 같은 오류를 반환하는 예입니다.

#include

void welcome( char * username ){
printf(“Welcome! %s\n”, username );
}
int main() {
const char * name = “hojin”;
welcome( name );
return 0;
}
결과 - compile warning:
warning: passing arg 1 of `welcome’ discards qualifiers from pointer target type

welcome은 분명 username이 가리키는 것을 사용만 할 뿐 바꾸는 것이 없습니다. 그런데도 선언이 const *가 아니므로, welcome 함수를 사용하기 위해 const를 무시하겠다는 내용입니다. 이것에 대한 해결책으로 name에 대한 const까지 없앤다구요? (char * name = “hojin”;) 제발 그러지 마세요. 꼬이는 지름길입니다.

의도를 나타내는 ‘const’ 멤버 함수
C++의 const 사용에 대한 예를 들기 전에 C++의 멤버 함수에 대해 살펴보기로 할까요. 모든 멤버 함수는 하나의 인자가 숨겨 있다고 생각해야 합니다. 바로 그 클래스에 대한 this 포인터입니다. 따라서 아무 것도 인자를 받지 않는 함수라 할지라도, 항상 this 포인터라는 최소 한 개의 인자를 받는다는 사실입니다. this 포인터가 모든 인자보다 먼저 전달된다고 생각합시다. 그러면, 이 this 포인터는 숨겨 있으므로 “const” 수식을 할 수 없지 않겠느냐고 생각할 수 있겠지만 그렇지 않습니다. 우선 C++의 const 사용에 대한 예를 들어 보겠습니다(<리스트 1>).

<리스트 1> C++ const 멤버 함수
#include
#include

class ZConfig {
protected:
char _strFileName[256];

public:
ZConfig(){};
~ZConfig(){};

void setFileName( const char * strFileName ) {
strncpy( _strFileName, strFileName, sizeof _strFileName );
}
const char * getFileName() const {
return _strFileName;
}
};

int main() {
ZConfig conf;
conf.setFileName("test.cfg");
cout << conf.getFileName() << endl;
return 0;
}

<리스트 1>은 getFileName 함수 뒤에 붙은 const의 예를 보여줍니다. 이것이 this 포인터에 대한 const 여부를 나타낸다고 생각하면 됩니다. 이것은 C로 해석하면 다음과 같은 형태로 이해할 수 있습니다. 컴파일될 코드는 아니지만 살펴보면,

setFileName( ZConfig * this, const char * strFileName ) {
strncpy( this->_strFileName, strFileName, sizeof _strFileName );
}

const char * getFileName( const ZConfig * this ) {
return this->_strFileName;
}

getFileName의 선언이 “const char * getFileName() const”가 아닌 “const char * getFileName()”으로 바꾸고 다음의 예에서 사용된다고 생각해 봅시다.

// getFileName의 const 여부에 따른 컴파일

class ZConfig {
..중략..
const char * getFileName() {
return _strFileName;
}
};

void run( const ZConfig * pConfig ) {
cout << pConfig->getFileName() << endl;
}

int main() {
ZConfig conf;
conf.setFileName(“test.cfg”);
run( & conf );
return 0;
}
결과 - Error:
In function `void run (const ZConfig *)’:
passing `const ZConfig’ as `this’ argument of `const char *ZConfig::getFileName ()’ discards qualifiers

C++에서는 const에 대한 처리를 warning으로 다루지 않고 error로 다루는 강력한 검사 기능을 제공하는데, 앞에 기록된 error는 “const char * getFileName()”와 같이 맨 뒤의 const를 제거한 형태로 컴파일할 경우에 발생합니다. 자, 여기서 개발자의 의도를 생각해 봅시다. 설계를 한다면 setFileName은 분명히 클래스 멤버 변수를 변경하는 의도가 있음을 알 수 있습니다. 따라서 이 함수 뒤에는 const가 따라오지 않을 것이라는 것이 분명합니다. 또한 run 함수의 의도는 ZConfig 객체가 읽기 전용으로만 사용될 것임을 예상할 수 있습니다. 그리고 그 안에서 사용된 getFileName도 멤버 변수를 읽는 함수라 생각되어 사용한 것입니다.
그런데 ZConfig에서 getFileName 함수 선언시 맨 뒤에 const를 넣어 두지 않으면, run 함수와 같이 객체의 const 포인터를 사용하여 멤버 함수를 호출하는 경우 const 포인터가 내용을 변화시키는 의도를 나타내므로 컴파일러는 오류를 내는 것입니다. 다음을 잘 생각해 보면 getFileName을 C 형태로 표현한 것이며, this 포인터가 const가 제거되는 상황임을 알 수 있습니다.

const char * getFileName( ZConfig * this ) {
return this->_strFileName;
}
void run( const ZConfig * pConfig ) {
cout << getFileName( pConfig ) << endl;
}

내부적으로는 this의 const 여부를 나타내는 것으로 해석하면, C++의 멤버 함수에 대한 것을 C의 표현법으로 해석할 수 있으므로 C++에서 const 함수라는 것이 왜 필요하게 되었는지 생각하는 데 도움이 될 것입니다. 이런 의도를 알게 되었다면, 다음부터는 컴파일러에게 객체의 변형에 대한 의도를 충분히 반영하여 장차 생길 수 있는 오류를 컴파일 타임 때 잡아내도록 노력합시다.

의도를 나타내는 ‘static’ 함수
C에서 static 함수의 표면적 의미는 ‘외부에서 불러 쓸 수 없는 그 파일 내부에서만의 함수’로 알려져 있습니다. 도대체 이게 왜 필요할까요? 이런 문법이 갖는 의도를 알지 못하는 이상 어떤 함수에 static을 줄지 말지를 심각하게 고민하지 않고, static은 전혀 사용하지 않는 편리한(?) 프로그램을 작성하게 됩니다. 잠시 링커를 생각해 봅시다. 링커가 하는 일은 오브젝트 파일들을 엮어서 실행 파일을 만드는데 있습니다. 엮는다는 의미는 외부에서 사용할 것이므로 어디엔가 함수 이름을 대비해 두고, 전 오브젝트에서 이름이 충돌하지 않게 관리된다는 추가적인 행동을 요구합니다. 안에서만 쓸 것이라 생각한 것들도 말이죠. 다른 말로는 이름 공간을 더럽힌다고 말합니다. 사용자 의도를 잘 해석하는 컴파일러는 <리스트 2>와 같은 경고를 보내줍니다.

VC++의 경고를 해석하면 “local function으로 만들었는데, 어느 곳에서도 사용하지 않으니 제거하겠다”는 뜻입니다. 사용자의 의도를 정확히 해석한 것이죠. 만약 함수 앞에 static이 없었다면 이런 경고를 내지 않을 것입니다. “다른 곳에서 사용하는가 보다”라고 해석하는 것이죠. static 함수라고 명시해 놓으면 나중에 프로그램을 고치다가 더 이상 쓸모없는 함수가 될 경우 즉시 컴파일러로부터 경고가 나올 것입니다. 그것에 따라 그 함수를 제거하면 프로그램 흐름에 대한 가독성을 높여 줄 것입니다. 이 static과 관련하여 헤더 파일 작성법도 약간의 영향을 받습니다.

◆ static이 아닌 것은 extern이 생략된 것이며, 이런 함수들은 모두 외부에서 사용되는 것이므로 헤더 파일에 선언을 한다.

◆ static인 것들은 .c 파일 전방에 선언한다. 혹은 사용하는 함수는 항상 뒤에 작성한다.

의도를 나타내는 클래스의 ‘static’ 멤버 함수
클래스의 static 멤버 함수와 일반 멤버 함수의 가장 큰 차이는 앞에서 언급한 this 포인터가 암묵적으로 전달되는지의 여부에 따라 다릅니다. C++ 책에도 나오듯이 static 멤버 함수는 일반 멤버 변수/함수에 접근하지 못하며, 단지 static 멤버 변수/함수만을 접근 가능하다고 알고 있을 것입니다. 이것은 static 멤버 함수는 this 포인터가 넘어가지 않는 함수이기 때문입니다. 따라서 this 포인터가 있어야만 하는 일, 앞과 같이 일반 멤버 변수/함수를 사용하는 호출에 대해 컴파일 오류가 생길 것입니다.

쓰레드를 만들 때 쓰레드의 입구 함수에 대한 형을 맞추는 것을 주의해야 합니다. 윈도우의 경우 CreateThread 함수를 사용하며, 유닉스의 Posix 쓰레드의 경우 pthread_create 함수를 사용합니다. 이 함수들은 인자에 입구 함수를 요구하며 각각 다음과 같은 형태의 함수 포인터여야 합니다.

Windows 쓰레드: DWORD func(void *);
Posix 쓰레드: void * func( void * );

문제는 다음과 같이 쓰레드 입구 함수에 클래스의 멤버 함수를 넣고 싶을 때 발생합니다. <리스트 3>은 posix 쓰레드를 사용한 것으로, XThread 클래스를 만드는 예제라고 가정하고 그 클래스에 두 개의 멤버 함수를 넣어 봅시다. 하나는 static 멤버 함수이며, 다른 하나는 일반적인 함수입니다.

<리스트 3>에서 사용된 pthread_create의 세 번째 인자로 들어가는 쓰레드 입구 함수는 앞의 코드와 같은 C 함수만 가능하다고 생각할 수 있습니다. 하지만 XThread에서 static 멤버로 선언된 thread_entrance1은 해당 요구사항을 만족하게 됩니다. 바로 this 포인터가 넘어가지 않기 때문에 가능한 것이죠. 직접 컴파일해 확인해 보기 바랍니다. 윈도우의 경우도 비슷하게 테스트해 볼 수 있습니다. 자, 이렇게 만들었을 때의 이점은 어떻게든 this 포인터를 받을 수 있다면(void *로 받는 param에 넘겨서) XThread의 protected 변수까지 접근 가능하다는데 있습니다.

const, static이 C++에서 많이 확장된 것을 확인해 보았습니다. 이런 내용은 오류 메시지를 잘 분석해 얻어질 수 있는 개념들입니다. C++ 명세에서 나왔다기보다는 C용 라이브러리와 같이 써야만 하는 환경해서 생각하다 보면 에러 메시지를 통해 얻을 수 있는 것입니다. 디버깅을 하면서 발생하는 컴파일 에러 메시지는 어떤 예제보다도 더 머릿속에 쏙 들어오는 문제집이자 참고서입니다.

헤더 파일 열어 보기
헤더 파일을 자주 열어 봐야 합니다. 즉, 유닉스 계열에서는 /usr/include 디렉토리, 비주얼 C++ 6.0에서는 VC98/include 디렉토리에 들어 있는 파일들의 내용을 이해한다는 것입니다. 이 헤더 파일은 사실 프로그래밍 초기에는 별로 보고 싶지 않은 내용으로 가득 차 있습니다. 그런 마음으로 프로그래밍을 하다가도 가끔씩 열어보곤 합니다. 하지만 여전히 신기한 문법을 사용하는 것 같아 보입니다. 헤더 파일이 복잡하게 보이는 것은 이식성을 고려해 만들기 때문입니다.

① WIN32와 MAC을 고려한 선언 부분을 발견할 수 있습니다.
② 32비트와 64비트에 따라 파일을 다루는 함수 등에서 파일 크기 등을 고려하여 달라지는 부분이 있습니다.
③ C와 C++ 동시에 사용되는 헤더 파일이 대부분이고, C용 헤더 파일의 경우에는 extern “C” 등이 항상 보입니다.
④ CPU의 endian에 따라 달라지는 부분이 있습니다.
⑤ ANSI C 이전의 컴파일러를 고려해 선언되는 인자를 없애고 선언해야 하는 경우도 있습니다.
⑥ 표준화(ANSI, X/Open, POSIX, BSD 등)에 따라 선언이 안되는 경우도 있습니다.
⑦쓰레드에 따라 달라지는 부분이 있습니다.
⑧예외(Exception)를 지원하는 않는 컴파일러를 고려해 달라지는 부분이 있습니다.
⑨디버깅(NDEBUG, DEBUG)에 따라 달라지는 부분이 있습니다.
⑩CPU 등의 아키텍처에 따라 달라지는 부분이 있습니다.

이렇게 많은 경우의 수를 하나의 헤더로 해결해야 하는 것이지요. 디버깅을 잘하려면 때때로 헤더 파일들을 뒤져가면서 보는 것이 좋습니다. 또 헤더 파일들을 잘 보면 앞과 같은 복잡한 상황에 대처하는 방법도 익히게 되며, 알지 못했던 상황도 고려하게 되는 경우가 많습니다. 디버깅을 위해서라도 헤더 파일 읽는 것을 소홀히 하지 마세요. 또, 한 가지 방법만 고려해 프로그램을 작성하다 보면 나중에 미처 생각지 못한 부분들이 발생하게 됩니다. 따라서 평소에 어떤 이식성 문제들이 있는지를 염두에 두면 디버깅할 때 입체적인 접근을 할 수 있습니다.

메모리에 대한 이해
메모리에 대한 이해는 코드를 작성할 때 데이터가 어떤 부분에 들어가는지에 대한 이해도입니다. 많이 접하는 네 가지의 예를 들어 보면 다음과 같습니다.
◆ 데이터
◆ static 변수(BSS)
◆ 자동 변수(stack)
◆ 힙

이중에서 데이터 영역과 BSS라 알려진 static 데이터 영역은 컴파일된 코드 내에 그 영역이 설정됩니다. 간단히 설명하면 데이터들은 static 변수에 들어가는 초기 값과 변수들이 저장되는 곳이며, BSS는 초기 값이 없는 static 변수가 들어가는 것이라고 보면 됩니다. 초기 값이 없고 변수 길이 정보만 잡힙니다(검색어 : data bss stack 세 개를 동시에 주면 자세한 내용을 더 알 수 있습니다). 다음 코드를 통해 익혀 봅시다(유닉스에서는 nm과 objdump를 통해서 확인해 볼 수 있습니다).

#include
const char * B;
const char * D = “R”;
int main() {
static int B2;
char * S = (char *) malloc( 32 );
S[0] = ‘H’;
return 0;
}

BSS 영역 : B, B2
데이터 영역 : D, “R”
스택 영역 : S
힙 영역 : S가 가리키는 곳, ‘H”가 저장되는 곳

앞 내용에 대한 것은 익숙해질 때까지 symbol 확인 유틸리티를 사용하고, disassemble 코드를 분석해 가면서 이해해야 합니다.

힙에서 흔히 발생하는 오류 형태
힙과 스택을 사용하는 데 생길만한 오류는 거의 바운더리 체크(boundary check)입니다. 먼저 GNU에서 제공하는 GNU C 라이브러리가 구현된 것의 개념만으로 설명하자면, malloc이 호출될 때 C 라이브러리는 요구한 크기의 연속된 메모리 공간(세그먼트라고 합시다)을 반환하여 줍니다. 그것은 다음과 같이 표현됩니다.

malloc에 의해 요청되는 크기에 8바이트 정도 추가 정보(A,B)가 먼저 기록되고 P 값이 리턴되어 넘어 옵니다. 커널에 요청하는 최초 메모리(A)가 넘어오는 것이 아니군요! 그리고 free로 해제할 때도 마찬가지로 P 값을 받아 8바이트를 뺀 위치에서 현재 해재돼야 할 길이를 구해 삭제 표시를 하게 되는 것입니다. 이런 이유로 free에서는 해제될 크기를 인자로 받지 않습니다. C++의 new, delete에서도 배열을 할당한 경우 delete[]를 호출할 때 원 배열의 크기를 넣지 않는 것도 같은 구현 방법으로 되어 있으며, 어떤 C++의 STL 구현에서 string에 대한 것도 내부 정보를 앞과 같은 방법으로 구현하는 것을 본 적이 있습니다. 중요한 것은 힙에서 버퍼 오버플로우가 일어날 때, 다음 블럭의 크기 정보를 망가뜨려 해제하거나 추가 할당할 때, 빈 공간에 대해 추정할 때 오동작하게 됩니다. 만약 오동작이 일어날 경우 이런 힙의 구조를 이해하면 추적하는 데 도움이 될 것입니다. new, delete도 결국에는 malloc, free를 이용하는 것입니다. 즉, 메모리를 할당받은 후 할당된 메모리에서 생성자나 소멸자가 불리는 것으로 이해하면 됩니다. 참고로 유닉스 계열에서 커널에 힙을 요청할 때는 내부적으로 brk 함수를 사용합니다.

스택에서 흔히 발생하는 오류 형태
스택은 흔히 번지 값이 감소하며 할당된다고 알려져 있습니다. 다음의 예와 같은 경우 <그림 2>와 같은 형태의 주소 배열을 갖습니다.

oid func() {
int x;
int y;
char buf[32];
}
buf가 나중에 선언되었지만 그 영향은 x, y에게 미친다는 것입니다. 또 스택이 사용되는 곳은 함수 호출과 관련되어 있습니다. 함수 호출은 calling convention이나 CPU 아키텍처마다 다릅니다. calling convention에 따라 함수에 넘어간 변수를 불린 함수가 해제하는 것이 있기도 하고, 부른 쪽에서 책임지고 해제하는 경우도 있습니다. 어떤 calling convention이나 CPU 아키텍처에 따라 함수 호출 인자의 몇 개까지는 레지스터에 넘기는 것도 있습니다.

함수가 호출될 때 일어나는 일은 돌아올 리턴 주소가 먼저 저장되며, 다음으로 프레임 포인터라는 것이 저장됩니다. 프레임은 각 함수의 단위로 생각하면 되는데, 그 함수 내에서는 모든 자동 변수들이 같은 베이스 포인터를 가지고 베이스 포인터로부터 얼마나 떨어져 있느냐로 표현됩니다. 스택 포인터는 늘 변하기 때문에 함수에 들어오자마자 프레임 포인터를 현재의 스택 포인터 값으로 바꿉니다. 예를 들어 <그림 2>를 살펴보면, frame pointer = 136이라 하고, frame pointer - 0을 x, frame pointer - 4를 y frame pointer - 36을 buf라 사용하는 것입니다. 따라서 하나의 함수가 시작하면 이전 함수의 프레임 포인터를 저장해 두어야 돌아가기 전에 복원됩니다(x86에서는 어셈블리어 leave 명령도 참고하세요).

스택 버퍼 오버플로우 공격이라 일컬어지는 것의 원리도 여기에 있습니다. buf에 쓰여지는 내용을 buf의 범위를 벗어난 리턴 어드레스까지 덮어 쓰게 만들고, 원래 호출한 함수로 돌아가는 것이 아니라 buf 내용 중간으로 점프하게 만들어 원하는 일을 하게 만드는 공격법이지요. 이런 이유 때문에 buffer 범위를 확인하지 않는 함수는 절대 사용 금지입니다(두 함수가 대표적입니다 : strcpy, sprintf). 정리하면 스택이 잘못될 경우 다음과 같이 영향을 미칠 수 있습니다.

① 갑자기 어떤 변수 내용이 바뀌었을 때, 그보다 아래 선언된 변수에서 영향을 받았을 가능성
② call stack이 이상하게 바뀌었을 경우에는 버퍼에 쓴 내용이 저장된 프레임 버퍼와 리턴 주소까지 영향을 준다.

원리를 알면 왜 그렇게 사용하지 말아야 하는가를 쉽게 이해할 수 있습니다. 원리를 모른 채 경고 메시지 제거나 프로그래밍 가이드를 따른다면 재미가 덜하겠죠? 디버깅은 경험한 만큼 언어와 컴파일러를 구현 원리까지 생각하도록 유도합니다.

C++의 함수 이름 꾸미기
C++에서 가장 초반에 공부하는 것 중의 하나는 함수 인자가 다르면, 같은 이름의 함수를 여러 개 만들 수 있다는 함수 오버로딩에 대한 것입니다. 그리고 C++에서 C에 대한 코드를 사용하려면 항상 extern “C” 지시자를 선언문에 넣어 두어야 제대로 사용되는 것을 배우게 됩니다. <리스트 4>를 보면 a1.c의 코드를 b1.cpp에서 사용하려면, a1.c에서 만든 함수에 extern “C”를 선언하는 것을 볼 수 있습니다.

이렇게 하는 이유는 C에 의해 생성되는 심볼과 C++에 의해 생성되는 심볼이 다르기 때문입니다. C에 의해 생기는 것은 함수명 그대로 심볼이 생기는 반면, C++에 의해 생기는 것은 함수명 뒤에 함수 인자에 따른 장식 문자들이 들어갑니다. <리스트 4>와 <리스트 5>의 a1.c, a2.cpp가 컴파일된 다음에 생기는 오브젝트의 심볼들을 살펴보면(<리스트 6>) C++에 의해 생성된 테스트에 대한 것은 “__Fii”라는 문자들이 붙게 됩니다. 아마 integer, integer라는 뜻이 맨 뒤에 붙었나 봅니다.

이런 문자들은 함수 인자에 따라 혹은 클래스 멤버에 따라 다양하게 준비되어 있습니다(윈도우에서는 OBJ 파일들에 대해 dumpbin /symbols라는 명령과 옵션으로 확인해 볼 수 있습니다). 이렇게 예상한 함수 뒤에 붙는 것을 함수 이름 꾸미기(function name mangling 혹은 function name decoration이라 하는데 적절한 번역이 없습니다)라고 합니다. 이렇게 하는 주된 이유는 함수 중첩 선언(function overloading)을 하기 위해 사용되는 오브젝트 파일 상에서의 기법입니다. 여기서 잘 생각해 볼 것은 C로 됐든 C++로 됐든 오브젝트 파일이 생기면 내부적으로는 사실상 같이 취급되는 것인데, 마찬가지로 포트란이나 파스칼도 오브젝트가 되면 링커에 의해 결합되는 것만을 남게 됩니다.

이런 원리를 알면 링커가 혼동하지 않도록 소스에서 오브젝트에 포함되는 심볼들의 이름을 일치시키는 것이 프로그래머가 해야 할 일입니다. 바로 extern “C”라는 선언문 앞 지시자의 역할이 함수 이름 꾸미기를 하지 말 것을 지시하는 것이지요.

nm a1.o
00000000 t gcc2_compiled.
U printf
00000000 T test

nm a2.o
00000000 t gcc2_compiled.
U printf
00000000 T test__Fii

재미로 한 가지 해 봅시다. 앞의 소스를 보면 b2.c라는 소스를 볼 수 있습니다만, 이것은 C++로 되어 있는 코드를 C에서 사용한 예를 나타낸 것입니다. 대개의 경우와 반대가 되겠지만, C에서 C++의 함수 이름 꾸미는 규칙에 대해 알고 일부러 없는 함수를 선언하여 링크되도록 유도한다고 해서 안 될 것이 없습니다. 다만 b2.c 같은 예제는 철저하게 재미로 만든 소스입니다. 결코 실전에서는 사용되어서는 안 됩니다. 왜냐하면 C++의 함수 이름 꾸미기 규칙은 컴파일러마다 완벽(?)하게 다르기 때문에 이름 규칙을 알고 소스를 작성하는 것은 무의미한 일입니다. b2.c 코드 또한 gcc에서 만드는 이름 규칙을 생각해서 만든 것이므로 다른 환경에서는 되지 않을 것입니다. 따라서 서로 다른 컴파일러에 의해 만들어진 C++ 코드는 이름 꾸미는 방식이 다른 것으로 인해 쉽게 같이 쓸 수 없는 단점이 있고, C++ 라이브러리는 컴파일러마다 독립적으로 존재한다는 것을 나중에 확인해 볼 수 있을 것입니다.

디버깅=프로그래밍 수련 과정
이번 호에서는 서로 관련 없는 사항이긴 하나 세 가지 정도를 들어 디버깅을 하면서 내부에서 돌아가는 원리를 알게 되는 일에 중점을 두어 설명하였습니다. 디버깅은 해킹과 같은 고도의 입체적인 접근과 연결되어 있는 개발 행위(?)입니다. 따라서 디버깅은 단순한 문제 해결 관점보다는 좀더 테스트 코드를 만들어 보게 하고, 언어와 환경에 대한 깊은 이해를 돕는 프로그래밍 수련회와 같은 것이라고나 할까요?

세 번에 걸쳐 디버깅에 대한 감각이 잡히려는 사람들을 대상으로 어떤 관점을 가져야 될지 주제를 골라 나열하였습니다만, 아는 것을 말로 표현하는 것이 쉽지만은 않다는 것을 느꼈습니다. 필자에게 따로 연락해도 도움을 드리겠지만, 되도록 지적인 공유를 위해 필자가 자주 이용하는 http://bbs.kldp.org/에 질문하면 여러 사람으로부터 다양한 도움을 얻을 수 있을 것입니다. 개발자들이 모두 디버깅에 자신을 갖고, 명랑한 코딩을 하기를 상상해 보면서 이만 연재를 마칩니다.


CRC ( Cyclic Redundancy Checks )

 

통신을 할때는 주위의 전자적인 영향 혹은 기타 요인으로 오류가 생길 수 있습니다

이러한 오류를 검출해야 될 필요가 있고.. 오류가 난 데이터에 한해서는 재 송신을 한다던지

조치를 취할 수 있어야 데이터를 주고 받을때 신뢰성을 갖게 됩니다

 

오류를 검출 해 내는 방법 -  parity Check, SumCheck 등 다양

 CRC 또한 오류를 검출 해내는 방법의 하나 

 

------------------------------------

T(x) = transmitting string           |

B(x) = given bit string              |

G(x) = generator polynomial     |

R(x) = remainder                    |

------------------------------------

 


이해가 안갈 듯 해서 실제 바이너리를 대입해서 설명하면.

4비트 생성자 값 G(x) = 1001 , D 는 11111010  이라고 했을때 CRC체크


G(x) 가 4자리의 비트이므로 D에 3자리를 더해서   11111010000  이 된다.

연산은 XOR이므로 나눌때 값이 작다고해서 나누지 못하는게 아닙니다.
                     1  1  1  0  0  1  1  0   
1001 |---------------------------
       |  1  1  1  1  1  0  1  0  0  0  0                            [ 모든 연산은 XOR 연산 ]
          1  0  0  1
        -----------
              1  1  0  1
              1  0  0  1
             -----------
                 1  0  0  0
                 1  0  0  1
                 ---------
                            1  1  0  0
                            1  0  0  1
                            -----------
                               1  0  1  0
                               1  0  0  1
                               ----------
                                      1  1  0             <- R  ( remainder )


전송되는 비트 ->  11111010110 ( CRC code )
검산

                    1  1  1  0  0  1  1  0
1001 |--------------------------
        | 1  1  1  1  1  0  1  0  1  1  0
         1  0  0  1
         -----------
             1  1  0  1
             1  0  0  1
             ----------
                1  0  0  0
                1  0  0  1          
               ----------
                           1  1  0  1
                           1  0  0  1
                           ----------
                              1  0  0  1
                              1  0  0  1
                               ----------
                                        0

출처 : http://dlrbtjd86.blog.me/92426289



참고 :
http://ko.wikipedia.org/wiki/%EC%88%9C%ED%99%98_%EC%A4%91%EB%B3%B5_%EA%B2%80%EC%82%AC

http://blog.bagesoft.com/858

  1. 알 수 없는 사용자 2021.04.07 05:43

    왕감사맨입니다.

  2. 811 2021.12.09 00:35

    1111101000 을 crc하면 마지막이 110이 나유네요 왜이렇죠

    • 811 2021.12.09 00:36

      제가 하면 0011이 나옵니다 이유
      마지막 자리 0을 1010으로 썻기에
      1010 과 1001 하면 0011이 됩니다..

리눅스 : FUSE : http://fuse.sourceforge.net/
윈도우 :  Callback File System : http://www.eldos.com/cbfs/spec.php
             Dokan : http://dokan-dev.net/en/

대체로 파일 시스템에 대한 제어 루틴은 커널 드라이버 제작을 통해 이루어졌다. 하지만 커널 드라이버 제작은 쉽지 않다. 위 3개의 프로젝트들은 커널 드라이버를 제작하여 파일 시스템을 구현하는 것이 아닌 유저 영역에서 파일 시스템을 구현할 수 있도록 지원해 준다. 기본 원리는 유저 역영에서 제작한 루틴(함수)를 FSUE, Callback File System , Dokan 드라이버가 대신 호출해 주는 것이다. 우리는 단지 파일시스템에 대한 루틴을 만들어 각 드라이버에 등록만 해주면 된다. 클라우드 스토리지 클라이언트에서 마운트/언마운트를 통한 클라우드 스토리지 접근을 운영체제에서 지원하는 실 저장공간처럼 느낄수 있게 해줄 수 있다. 마치 NFS, CIFS 같은 느낌이랄까..

참고 사이트:
유저모드에서 파일시스템 드라이버를 만들기: http://www.benjaminlog.com/entry/device-driver-in-user-space
FUSE 파일 시스템 Overview : http://kernelstudy.tistory.com/tag/FUSE
Ndriver 개발자 센터 : http://dev.naver.com/opensource/compliance/

  1. 오곡 2012.11.26 11:06

    좋은 내용 잘봤습니다 ^^


php5 는 소스를

<? 는 <?php 로
<?= 는 <?php echo 로
바꾸어야한다.

이렇게 바꾸지 않기위해서는

php.ini 에서

short_open_tag = off 를

short_open_tag = on 으로 바꾸어 주어야 한다.

http://radiocom.kunsan.ac.kr/lecture/mysql/API/API.html
http://www.cinsk.org/cfaqs/html/node1.html 


질문과 답변이 아주 잘 정리되어있다. 근래 찾은 곳중에 으뜸이다.
개정된 표준에 대한 정보는 아래의 웹 사이트를 확인하라.

http://www.open-std.org/jtc1/sc22/wg14/

http://www.lysator.liu.se/c/index.html
http://www.dmk.com/ 
곱하기 연산(2의 배수)
x = x * 2;
x = x * 64;

//equals
x = x << 1;
x = x << 6;


나누기 연산(2의 배수)
x = x / 2;
x = x / 64;

//equals
x = x >> 1;
x = x >> 6;


정수로 변환
x = int(1.232);

//equals
x = 1.222 >> 0;


색 추출
// 24bit
var color:uint = 0xff336699;
var a:uint = color >> 16;
var g:uint = color >> 8 & 0xff;
var b:uint = color & 0xff;

//32bit
var color:uint = 0xff336699;
var a:uint = color >> 24;
var r:uint = color >> 16 & 0xff;
var g:uint = color >> 8 & 0xff;
var b:uint = color & 0xff;


색 병합
//24bit
var r:uint = 0x33;
var g:uint = 0x66;
var b:uint = 0x99;
var color:uint = r << 16 | g << 8 | b;

//32bit
var a:uint = 0xff;
var r:uint = 0x33;
var g:uint = 0x66;
var b:uint = 0x99;
var color:uint = a << 24 | r << 16 | g << 8 | b;


임시변수 없이 XOR 을 사용하여 정수 교환
var t:int =a;
a=b;
b=t;

//equals
a ^= b;
b ^= a;
a ^= b;


증감/가감 연산
기본 ++,-- 보다 느리다. 코드를 복잡하게 할 수 있다.
i = -~i; // i++
i = ~-i; // i--


NOT 혹은 XOR을 이용한 부호변환
i = -i;

//equals
i = ~i + 1;

//or
i = (i ^ -1) + 1;


AND 연산을 사용한 나머지 연산
2의 배수로 나눌때만 사용 가능하다.
modulus = numberator & (divisor - 1);

x = 131 % 4;

//equals
x = 131 & (4-1);


절대값구하기
//version 1
i = x < 0 ? -x : x;

//version 2
i = ( x ^ ( x >> 31)) - ( x >> 31);


부호 비교
eqSign = a * b > 0;

//equals
eqSign = a ^ b >=0;

 

출처 : http://lab.polygonal.de
출처 : http://blog.naver.com/PostView.nhn?blogId=c96jks&logNo=130050823702&redirect=Dlog&widgetTypeCall=true


다음은 배치 프로그래밍의 대가인 티모 살미 교수가 정리한 것입니다.
아주 유용한 테크닉들이 들어있습니다.


1. "@echo off"를 일반적으로 사용하기
====================================
화면에 명령어들이 표시되지 않게 echo off 하고, 그 라인도 화면에 표시 되지 않게 하기 위해서 다음과 같이 하면 된다.
@echo off
이 것은 MsDos 3.30 이후 버전에서만 작동한다. 이것을 일반적으로 사용하게 하기 위해서 3.30이상의 MsDos를 사용한다면 autoexec.bat 안에 다음과 같이 적어 놓는다.
set _echo=@
그리고 배치파일에서 다음과 같이 사용한다면 어느 버전의 MsDos버전에서도 작동한다.
%_echo%echo off

2. 모든 파일을 지우기
=====================
가장 흔하게 질문되는 것(FAQ)중의 하나는 del *.* 을 사용껦 때,"Are you sure (Y/N)?" 라는 확인을 어떻게 하면 나타나지 않게 하는것이다. 다음과 같이 사용한다.
echo y| del *.*
화면에 나타나는 메세지도 보이지 않게 하려면 다음과 같이 한다.
echo y| del *.* > nul
이러한 확인 절차를 표시하지 않게 하는 것은 토론의 여지가 많지만,위와 같이 사용할 수 있다.

3. 다중 반복
============
배치파일에서 다중 루프(반복)를 사용하는 것이 가능하다. 다음의 두배치파일을 생각해 보자. 그리고 test.bat을 불러 실행시켜 보자.
echo off
rem TEST.BAT
for %%f in (a b c d e f) do %comspec% /c test2 %%f

echo off
rem TEST2.BAT
for %%g in (1 2 3) do echo %1%%g
아니면 한줄로 다음과 같이 써서 사용할 수도 있다.
for %%f in(a b c d e f) do %comspec% /c for %%g in (1 2 3) do echo %%f%%g
이 두번째 방법의 단점은 echo가 화면에 표시된다는 것이다.

4. 디렉토리가 존재하는지 확인하는 방법
======================================
디렉토리가 있는지 확인하는 것은 가끔 매우 쓸모있는 일이다. %1의 디렉토리가 없다면 다음 확인은 참이 될것이다.
if not exist %1\nul if not exiat %1nul echo Directory %1 does not exist

5. 프로그램을 현디렉토리나 경로에서 사용할 수 있는지 확인하기
====================================
배치 프로그램에서 프로그램을 불러서 사용할때, 그 파일에 대한 경로를 써주지 않았을 경우, 그 프로그램이 현재의 디렉토리나 경로에서 사용가능한지 확인할 때 도움이 될 것이다.
set _found=
if exist %1 set _found=yes
for %%d in (%path%) do if exist %%d\%1 set _found=yes
for %%d in (%path%) do if exist %%d%1 set _found=yes
if "%_found%"=="yes" goto _continue
echo %1 is not at path or the current directory
goto _out
:_continue
echo %1 found at path or in the current directory
:_out

6. 배치파일에서 서브루틴이나 재귀적방법을 사용하기
====================================
배치파일 안에서 서브루틴을 사용하는 것은 가능하다. 방법은 서브루틴이 실행된 뒤에 돌아가야할 곳을 가르키는 환경변수(예를들면_return)를 설정하는 것이다. 이런 예는 UNPACK.BAT 이나 BOOT.BAT의:_common 과 :_subru 부분에서 찾아 볼 수 있다.
마찬가지로 재귀적인 사용이 가능하다. ("재귀적인 방법"의 의미는 한 배치파일이 자기 자신을 불러 사용하는 것이다.) 이 예는 SAFEDEL.BAT에서 아래의 행을 따라 찾아 보면 된다.
for %%f in (%1) do call safedel %%f recurse
배치파일의 0번째 인수(%0)는 배치파일 자신을 나타내므로, safedel은 %0으로 대치 되어 사용할 수도 있다.

7. 매개 인수(parameter)를 대문자로 바꾸기.
====================================
다음은 배치파일에 사용한 인수 %1 를 대문자로 바꾸어 주는 예제이다. 이는 MsDos는 path를 대문자로 바꾼다는 점을 이용한 것이다. 결과는 upcase_에 저장될 것이고, 원래의 경로가 다시 저장될 것이다.
set tmp_=%path%
path=%1
set upcase_=%path%
path=%tmp_%

8. 새로운 디렉토리를 경로에 붙이기
====================================
자주 필요한 이 기술은 매우 간단하다. 예를 들어 %1를 경로에 덧붙이려면
path=%path%;%1
이라고 하면된다.
이 기술은 배치파일 안에서만 사용할 수 있다. 배치파일 안에서만 환경변수(%path%)를 사용할 수 있기 때문이다. 존재하지 않는 디렉토리를 덧붙이려한다거나 중복해서 경로를 덧붙이는 것을 방지하는 ADDPATH.BAT이라는 배치파일이 있다.

9. 두 파일을 비교하기
====================================
배치파일에서 두 파일이 같은지 아닌지 확인해 볼 수 있다. 이 기술은 MsDos의 외부 명령어인 fc.exe와 find.exe를 사용한다. (외부 명령어라는 뜻은 MsDos와 같이 있는 프로그램들이다. 대부분의 외부 명
령어용 프로그램들은 c:\dos 에 위치한다.)
fc %1 %2 > tmp$$$
type tmp$$$ | find /i "fc: no differences encountered" >diffe$$$
if exist notsame$ del notsame$$$
copy diffe$$$ notsame$ > nul
if not exist notsame$ echo Files %1 and %2 are different
if exist notsame$ echo Files %1 and %2 are identical
if exist tmp$$$ del tmp$$$
if exist notsame$ del notsame$
if exist diffe$$$ del diffe$$$
좀더 생각하면 이 기술은 다른 목적에도 사용할 수 있다. 이는 파일안에 주어진 문자열이 있는지 확인 하는데 바탕을 두고 있기 때문이다.

10. 빈줄을 쓰기
====================================
이는 간단하지만 종종 필요하고 유용한 기술이다. echo 바로 다음에점(.)을 찍으면 빈줄을 표시할 수 있다.
echo.

11. pause를 이용해 메세지를 표시하기
====================================
메세지를 손쉽게 나타나게 할 수 있다. 메세지를 echo한 다음 pause 를 사용하는데, pause의 메세지를 nul로 보내면 된다.
echo Break to quit, any other key to remove the tmp directory
pause > nul

12. for를 이용한 다양한 rename 기술
===================================
이 기술이 기본적이고 사소하지만, 이를 생각해 내기란 쉽지 않을 것이다. for 문은 파일의 이름을 바꾸는데 특별히 유용하다. 예를 들면, 내가 다음의 파일들을 가지고 있을 때, (터보 파스칼 TP 4.0,
5.0, 5.5, 6.0) 내가 버전 29를 30으로 바꾸기 원한다고 할때,
tspa2940.zip
tspa2950.zip
tspa2955.zip
tspa2960.zip
다음은 손쉽게 그런 일을 해준다.
for %f in (40 50 55 60) do re tspa29%f.zip tspa30%f.zip
물론 파일이름 바꾸는 일 말고도 이 기술로 다양한 일을 할 수 있다.
하나의 예는 다음과 같다.
for %d in (a b) do format %d:

13. 와일드카드를 확인하기
====================================
이 예제는 인수 %1이 와일드 카드를 사용하고 있는지 아닌지 확인한다.
@echo off
for %%f in (%1) do if "%%f"=="%1" goto _nowilds
echo Parameter %1 contains wildcards (or is missing)
:_nowilds

14. 배치 작업을 중간에 그만두지 못하게 하기
====================================
ctty 명령어를 사용해서 입력장치나 출력장치를 새로 설정하여 배치파일을 중단시키는 것을 방지할 수 있다. 여기의 예제는 패스워드로 e를 넣어야 하는 간단한 배치파일이다.
ctty가 nul로 돌려진 동안<,>의 리디렉션이 필요한 것을 눈여겨 보라. ask라는 배치파일을 돕
기 위한 프로그램은 같이 포함되어 있다. ( MsDos의 choice와 비슷하다. 단, 에러 레벨을 입력한 문자의 아스키 값으로 돌리는 것만 틀리다.)
@echo off
ctty nul
echo Now you cannot break the batch with ^C or ^Break > con
:_ask
echo Use e to break > con
ask /b /d < con
if errorlevel==101 if not errorlevel==102 goto _out
goto _ask
:_out
ctty con
echo Back to normal. Now you can break the batch with ^C or
^Break.
이 배치파일이 작동되고 있는 동안에는 alt-crtl-del로 다시 부팅할수도 없다. 이 같은 일을 하는 noboot.exe라는 램상주 프로그램도 있다.

15. autoexec.bat를 중지하고 건너뛰는 것을 방지하기
====================================
브레이크를 눌러 autoexec.bat를 건너 뛰어 지나치지 않게 하기 위해서 다음과 같이 config.sys에 쓰면 된다.
shell=c:\command.com /p nul
이렇게 하기 전에 만일의 경우를 대비해서 플로피 디스켓으로 부팅할준비를 해둔다. autoexec.bat 맨 뒷줄에 'ctty con'이라고 덧 붙여야 된다. 그렇게 하지 않으면 키보드가 말을 듣지 않을 것이고, 준비한 플로피 디스켓으로 부팅해야 할 것이다 :-).

16. 확장자를 인식하기
====================================
단지 확장자를 확인하려던가, 주어진 파일의 이름에서 확장자를 환경변수로 저장하려고 할때, 이 것은 매우 유용하다. 어떻게 하는지 여기에 있다. 이 배치파일은 PC-Magazine July 1992, Vol 11, No. 13,
page 528에 나온 정보를 이용한 것이다. for 루프에서 슬레시(/)로 시작하는 인수는 두 부분으로 나누어지는데, 처음 부분은 인수의 첫문자이고 다른 부분은 나머지 문자열이다.
이 해결방법에서 하나의 문제점은 .* 이라던가 .??? 이란 확장자를 인식하지 못하는 것이다. 그러나 "와일드카드를 확인하기"를 이용해서 확인하면 될 것이다. 이러한 기술을 이용한 것중에 UNPACK.BAT라
는 배치파일이 있다.
@echo off
set exten_=%1
:_next
set prev_=%exten_%
for %%f in (/%exten_%) do set exten_=%%f
if ".%exten_%"=="%prev_%" goto _extfound
if not "%exten_%"=="%prev_%" goto _next
goto _noext
:_extfound
echo The filename %1 has an extension %exten_%
goto _out
:_noext
echo The filename %1 has no extension
:_out
set exten_=
set prev_=

17. % 문자 인용부호
====================================

%1은 배치파일에 주어진 첫번째 인수를 가르킨다. 이처럼 'echo %1'이라고 하면 첫번째 인수를 표시해 준다. 대신에 %1라는 문자를 표시하고 싶은 경우 어떻게 해야하는가? % 문자는 인용부호처럼 행동한다. 그래서 %%1이라고 쓴 경우 실제로는 "%1"이라고 화면에 표시된다. 아래의 간단한 연습을 실행해보라.
@echo off
if "%1"=="" goto _out
echo %1
echo %%1
:_out
이 기능을 이용한 것은 "배치의 보조 배치파일을 없애기"를 보아라.
좋은 예로는 DELPATH.BAT가 있다.

18. 배치의 보조 배치파일을 없애기
====================================
많은 배치 프로그램이 call을 사용해서 보조 배치파일을 불러다 쓴다. 많은 경우 이런 일을 재귀적인 사용을 통해 자기 자신을 불러다씀으로써 보조 파일을 사용하는 것을 줄일 수 있다. 보조코드는 배치파일 자기자신에 넣어 놓는다. 이러한 기술은 와일드 카드를 받아들이는 TYPE 같은 SHOW.BAT 에서 가장 잘 나타나 있다. 일반적으로는 개개의 파일을 type하기 위해서 보조파일이 필요하다. 다른 예는
SAFEDEL.BAT에서 찾아볼수있다.
이와 같은 일을 하기 위한 다른 기술이 있다. 원래의 배치파일이 보조 배치파일을 만든 다음 그것을 불러 사용하는 것이다. 이런 것으로는 DELPATH.BAT의 예를 들 수 있다. 여기에는 사용되는 드라이브를
보여주는 간단한 예가 있다. (c 부터 t 까지 가능하다. 여기선 더 쓰면 줄이 넘어가니까!)
@echo off
echo @echo off> tmp$$$.bat
echo if exist %%1:\nul echo Drive %%1: is present>> tmp$$$.bat
for %%d in (c d e f g h i j k l m n o p q r s t) do call tmp$$$
%%d
del tmp$$$.bat
디스크의 볼륨 레이블을 찾아내는 창의적인 기교가 PC-Magazine August 1992, Vol. 11, No. 14, p. 527에 실렸다. 여기는 같은 기술을 사용하는 예가 있다. 환경변수 getdir_에 현재의 디렉토리를 저장한다. 이 기술은 PUSHDIRE.BAT에 사용되고 있다.
@echo off
echo @echo off> director.bat
echo set getdir_=%%2>> director.bat
echo echo %%getdir_%%>> director.bat
dir | find "Directory"> go.bat
call go
if exist director.bat del director.bat
if exist go.bat del go.bat

19. subst 명령어를 경로에 사용하기
====================================
어떤 디렉토리를 읽기 쉽게 하기 위해서 간단한 배치파일을 사용한다. 만약 subst 가 이미 설정되어서 생길 수 있는 에러를 방지한다. 그리고 마지막으로 현재 대치된 디렉토리의 현황을 보여준다.
@echo off
if exist m:\nul echo The substitution has already been made
if not exist m:\nul subst m: c:\math
if not exist s:\nul subst s: c:\support
subst

20. 일주일에 한번 실행하기. (요일을 확인하기)
====================================
요일을 환경변수에 넣는 것은 어려운 기술이다. 완전한 예는 WEEKLY.BAT에서 찾아볼수 있다. 이 기술의 핵심은 아래에 나와 있는데, 요일을 weekday_라는 환경변수에 저장하는 것이다. 일반 도스 프로그램 외에 아무런 보조 프로그램이 필요없다.
@echo off
echo.| date | find "Current" > tmp$$$.bat
echo set weekday_=%%3> current.bat
call tmp$$$
echo %weekday_%
if "%weekday_%"=="Fri" echo Thank God it's Friday
if exist tmp$$$.bat del tmp$$$.bat
if exist current.bat del current.bat
set weekday_=
사실, 위에서 %%3 대신에 %%4를 사용하면 오늘의 날짜를 확인할 수 있다.

21. 파일이름에 경로가 포함되었는지 확인하기
====================================
우선 먼저 "확장자를 인식하기"를 보면 같은 아이디어인 것을 알 수 있다. 파일이름이 단순히 go.exe 로 이루어 졌는지, 아니면 경로를 포함해서 r:\progs\go.exe와 같이 이루어 졌는지 확인하는 것은 r:\progs\*.exe와 같이 확장자를 사용했다면 매우 복잡한 일이다. 여기서 어떻게 되는지 설명하였다. 이를 완전히 이해했다면 확실히 배치 파일들에 대해서 이해하기 시작했다고 말할 수 있을 것이다.
@echo off
echo @echo off> tmp$$$.bat
echo set rest_=%%1>> tmp$$$.bat
echo :_next>> tmp$$$.bat
echo set prev_=%%rest_%%>> tmp$$$.bat
echo for %%%%g in (/%%rest_%%) do set rest_=%%%%g>> tmp$$$.bat
echo if ":%%rest_%%"=="%%prev_%%" goto _found>> tmp$$$.bat
echo if "\%%rest_%%"=="%%prev_%%" goto _found>> tmp$$$.bat
echo if not "%%rest_%%"=="%%prev_%%" goto _next>> tmp$$$.bat
echo goto _nopath>> tmp$$$.bat
echo :_found>> tmp$$ at
echo set haspath_=yes>> tmp$$$.bat
echo goto _out>> tmp$$$.bat
echo :_nopath>> tmp$$$.bat
echo set haspath_=no>> tmp$$$.bat
echo :_out>> tmp$$$.bat
echo set rest_=>> tmp$$$.bat
echo set prev_=>> tmp$$$.bat
for %%f in (%1) do call tmp$$$ %%f
if "%haspath_%"=="yes" echo Filename %1 includes a path
if "%haspath_%"=="no" echo Filename %1 does not include a path
rem if exist tmp$$$.bat del tmp$$$.bat
set haspath_=

22. 엔터키를 누르지 않고 시간을 보기
====================================
현재의 시간을 보는 간단한 기술은 다음과 같다.
echo.| time | find /v "new"
시간을 환경변수로 저장하는 방법은 LASTBOOT.BAT을 보아라.

23. 에러레벨 값을 확인하는 다른 방법
====================================
많은 프로그램과 몇개의 도스명령어들( diskcomp, format, xcopy)은끝날 때 에러 레벨을 발생시킨다. 에러레벨의 누적적인 성질 때문에 에러 레벨을 확인하는 것은 다소 복잡해진다. 그래서 만약 에러레벨이 정확히 2인지 확인하기 위해서는 다음과 같이 한다.
if errorlevel==2 if not errorlevel==3 echo Errorlevel 2
for 명령어를 사용하는 다른 방법으로 다음을 들수 있다.
for %%e in (0 1 2 3 4 5 6 7) do if errorlevel==%%e set
_errlev=%%e
if "%_errlev%"=="2" echo Errorlevel 2
좀 더 일반적으로 다음과 같이 할 수 있다.
for %%e in (0 1 2 3 4 5 6 7) do if errorlevel==%%e set
_errlev=%%e
if "%_errlev%"=="2" echo Errorlevel %_errlev%
복잡한 배치파일에서 편리한 방법은 goto를 사용하는 것이다.
for %%e in (0 1 2) do if errorlevel==%%e goto _label%%e
goto _out
:_label0
echo Errorlevel 0
:_label1
echo Errorlevel 1
:_label2
echo Errorlevel 2
:_out
이 기술을 실제로 사용하는 예는 BOOT.BAT에서 찾아볼수 있다.

24. 배치파일의 출력을 리디렉션(redirection)하기
====================================
배치파일 안에서의 출력은 손 쉽게 재 방향전환(redirecion)할 수 있다. 다음과 같은 example.bat 이라는 배치파일을 생각해보자.
@echo This is a redirection test> test
"example"를 실행시키면 아래의 문장을 담은 "test"라는 파일을 생성 할 것이다.
This is a redirection test
이 줄은 eoln(end of line: ascii 13 + 10)을 줄 끝에 포함하고 있다. 리디렉션 기호 '>' 앞에 아무런 공백도 주지 않는 것이 현명할때가 있다.
배치파일이 만드는 출력을 다시 재 방향전환(redirection)하는 것은 다소 복잡하다. 다음과 같은 내용을 지닌 example2.bat을 생각해 보자.
@echo This is another redirection test
실행하면,
example2 > test
출력은 화면에 나오고, 빈 test라는 파일이 생성될 것이다. 출력을 재 방향 전환 시키기 위해서는 다음과 같이 command.com 명령어 해석기를 통해서 배치파일을 실행해야 한다.( command.com은 현디렉토리나 경로에 있어야 한다.)
command /c example2 > test
이와 같이 하면 내용이 "test"라는 파일에 담길 것이다.

25. 환경저장 공간이 충분한지 확인하기
=====================================
만약 배치파일이 환경저장 변수를 사용하면, 환경저장 공간이 부족할경우가 있다. 만약 "Out of environment space"라는 메세지를 받는다
면 잘 알려진 방법을 통해서 다음과 같이 config.sys 의 shell을 설정해서 환경저장 공간을 늘릴 수 있다.
shell=c:\bin\command.com c:\bin /e:1024 /p
이 보다 덜 알려진 기술로는 환경저장 공간이 모자라기 전에 미리 확인해 볼수 있다. 아래의 예는 32바이트의 환경이 남아 있는지 확인한다.
@echo off
set test_=12345678901234567890123456789012
if "%test_%"=="12345678901234567890123456789012" goto _yes
echo Insufficient environment space
goto _out
:_yes
echo Sufficient environment space
set test_=
rem Whatever you wish to do
:_out

26. 드라이브를 사용 못하게 하는 간단한 방법
====================================
임시로 드라이브를 사용하지 못하게 하려면, subst명령어를 사용하면 된다. 예는 아래와 같다.
@echo off
md c:\none
subst d: c:\none
다시 사용하게 하려면,
@echo off
subst d: /d
rd c:\none

27. 프린터에 escape 명령어를 보내기
===================================
여기 정말 사소한 기술이 있다. 명령행에서 곧바로 프린터에게 escape sequence를 보낼 수 없다. 그러나 다음과 같은 배치파일을 이용하면 간단하다.
@echo ESC%1> prn
ESC는 진짜 escape문자로 에디터로 쓰여져야 된다. 이 방법의 한가지 결점은 라인피드를 보내는 것이다.

28. 무작위 문자열을 만든는 방법
===============================
UseNet news에서 무작위 문자열을 만드는 방법을 물어보는 사람이 있었다. 대답은 다음과 같다. 이를 확장해서 공부해보기 바란다.
@echo off
echo 10 randomize(val(mid$(time$,7,2))) > tmp.bas
echo 20 open "tmp2.bat" for output as #1 >> tmp.bas
echo 30 x$ = mid$(str$(int(rnd*10000)),2) >> tmp.bas
echo 40 print #1,"@set ramdom_=";x$ >> tmp.bas
echo 50 close #2 >> tmp.bas
echo 60 system >> tmp.bas
gwbasic tmp.bas
call tmp2
del tmp.bas
del tmp2.bat
set

29. 문자열의 길이를 알아내기
============================
문자열의 길이를 찾아내는 일은 PC Magazine January 26, 1993 issue 에 실렸다. 여기서 제안하는 방법은 PC 메거진의 방법과 근본적으로 같지만, 더 일반적이다.
@echo off
set test_=Testing the lenght of a string
echo %test_% > len$&$&$
dir len$&$&$ | find "LEN$&$&$" > go$$$.bat
echo @echo off> len$&$&$.bat
echo set length_=%% len$&$&$.bat
call go$$$
echo The lenght is %length_% bytes
del len$&$&$
del len$&$&$.bat
del go$$$.bat

30. MsDos의 버전을 환경변수로 저장하기
======================================
ADJCURS.BAT을 보면 알겠지만, 배치파일로만 버전을 알아낼 수있다.
여기에 다른 방법이 있다.
@echo off
ver > go$$$.bat
echo @echo off> ms-dos.bat
echo set version_=%%2>> ms-dos.bat
call go$$$
echo Your MsDos version is %version_%
del go$$$.bat
del ms-dos.bat




출처: http://blog.naver.com/darkstorm001/40017851898

③ 유니캐스트, 브로드캐스트, 멀티캐스트


유니캐스트, 브로드캐스트, 멀티캐스트는 네트워크에서 통신하는 방법을 구분 짓는 방법 입니다.


유니캐스트 - 1:1통신 방법입니다. 데이터를 보내고자 하는 주소 (맥어드레스)를 프레임에 포함시켜 보내는 방식입니다. 그래서 그 맥 어드레스를 찾아 통신하게 되고 같은 네트워크에 있는 노드들은 자신의 맥 어드레스 아닌 경우엔 패킷이 CPU 까지 전송되지 않고 LAN카드에서 "맥 어드레스가 틀리네" 하면서 버리게 되는 것 입니다. 그래서 CPU까지 영향을 미치지 않고 원하는 노드랑 통신이 가능 한 방식 입니다.


브로드캐스트 - 하나의 네트워크 전체의 통신방법 입니다. 같은 네트워크에 포함된 장비들에게 거부권은 없고 일단 무조건 수신하고 봐야하는 통신법 입니다. 예를 들어 동네이장님이 마이크로 마을 전체에 방송하는 것 과 같은 원리입니다. 일단 방송하면 싫어도 듣게 되겠죠? 그런 원리입니다. 유니캐스트 와는 다르게 무조건 받아들어야 하기 때문에 CPU까지 패킷이 올라가게 되고, 컴퓨터 자체에 부담이 증가하게 되는 것입니다.
 
브로드캐스트의 대표적인 사용 예는 ARP입니다. 맥어드레스 설명할때 잠깐 나온 ARP에 대해 설명 드리겠습니다. ARP 란 자신과 데이터 통신을 하기위한 다른 노드의 맥어드레스를 알아내기 위한 프로토콜입니다. 쉽게 말해 실직적인 통신은 IP주소가 아닌 맥어드레스로 이루어지는데, IP주소는 알고 잇지만 맥어드레스를 모를 때 사용하는 방법 입니다.

예를들어(ARP) ..
길동, 영수, 순이 , 철수란 이름을 가진 아이들이 있습니다. 영수는 순이라는 아이의 지갑을 주웠습니다.
영수가 아이들에게 "순이가 누구냐?" 하고 물었습니다.
그러자 순이가 "내가 순이야" 라고 대답을 했죠,
영수는 순이에게 지갑을 건 내 줬습니다.

이때 길동, 영수, 순이, 철수는 각각의 컴퓨터라고 생각 한다면,
영수가 순이라는 아이의 지갑을 주워서 돌려주기 위해서는 순이가 누구지를 알아야 합니다.
그래서 "순이가 누구냐?" 하고 물었죠?
이때, 영수의 질문은 불특정 다수에게 질문을 한 것이고, 이게바로 브로트 캐스트 입니다.
그리고 이 질문을 들은 아이들은 ARP를 동작 합니다. '내이름이 순이가 맞나?' 하고 생각을 하는 것이죠. 그리고 순이 가 아닌 다른 아이들은 순간 멈칫했지만, 자신이 아니므로 무시하고 하던 일을 계속합니다. 순이는 대답을 했겠죠 영수가 대답을 한 순이 에게 지갑을 돌려줍니다(이게 유니캐스트 입니다.)

만약, 철수가 순이라는 아이를 알고 있다고 하면, 브로드캐스트로 모두에게 물어봤을까요?
아닙니다. 알고 있다면 바로 순이에게 유니캐스트를 시도하게 되는것입니다.




멀티캐스트 - 약 150여명의 사용자가 있는 한 네트워크에서 100명 에게 데이터를 전송 하기 위한 상황이라면 100명에게 일일이 유니캐스트로 보낼 수도 없고 100명을 위해 50명은 무시하고 브로트캐스트로 보낼 수도 없고, 이럴 때 사용 하는 게 멀티캐스트 입니다.

멀티캐스트의 원리는 멀티캐스트 전송을 위해서는 헤더에 수신자의 주소 대신 수신자들이 참여하고 있는 그룹주소를 표시하여 패킷을 전송 한다. 멀티캐스트 전송을 위한 그룹 주소는 D-class IP 주소(224.0.0.0~239.255.255.255)로 전세계 개개의 인터넷 호스트를 나타내는 A, B,C-class IP주소와는 달리 실제의 호스트를 나타내는 주소가 아니며, 그룹 주소를 갖는 멀티캐스트 패킷을 전송받은 수신자는 자신이 패킷의 그룹에 속해 있는 가를 판단해 패킷의 수용여부를 결정합니다. 그러나 현재 인터넷상의 라우터들이 대부분 유니캐스트만을 지원하기 때문에 멀티캐스트 패킷을 전송하기 위해서는 멀태캐스트 라우터 사이에 터널링(tunneling)이라는 개념을 사용하여 캡슐화(encapsulation)된 채킷을 전송 합니다. 즉 멀티캐스트 주소를 가진 데이터 패킷 헤더 앞에 멀티캐스트를 지원하지 않는 일반라우터들을 거칠 때 기존의 유니캐스트 패킷고 같은 방법으로 라우팅 되어 최종적으로 터널의 종착지로 전송될 수 있게 하는 것입니다.

출처 : http://bongsnet.tistory.com/15

 




___________________________________________________________________________________________




IP주소의 클래스
IP 주소는 그 활용도에 따라서 A, B, C, D, E 클래스로 구분되어 지고 A, B, C 클래스의 경우는 일반 사용자를 위한 클래스 이고 D클래스는 멀태캐스트를 위한 IP주소이고, E 클래스는 실험을 위한 테스트용 입니다.

● A 클래스

사용자 삽입 이미지

                            # Bits        1                      7                                      24

첫번째 칸 : A 클래스라는 것을 알려주기 위한 비트
두번째 칸 : 네트워크 부분
세번째 칸 : 호스트 부분

으로 나눌 수 있습니다. 그러므로 A 클래스는 항상 '0' 으로 시작 되어야 하고, 네트워크 부분의 비트는 7개 호스트 부분의 비트는 24개 로 정해져 있습니다. 그래서 A 클래스의 호스트수는 다른 클래스 보다 가장 많으며, 네트워크 번호는 1~ 126 까지 입니다. 그렇다면 왜 126 까지 인가? 2진수로 따져보겠습니다.

A클래스의 가장작은 수는 0000 0000.0000 0000.0000 0000.0000 0000 ~10진수~> 0.0.0.0
A클래스의 가장큰 수는 0111 1111.1111 1111.1111 1111.1111 1111 ~10진수~> 127.255.255.255

가 됩니다. 그럼 1~127 까지 아닌가 라고 생각 하실텐데 127번 대역은 호스트 자신의 주소로 하라고 따로 정의가 되어 있습니다. 그래서 A 클래스의 네트워크 부분은 1~126 까지가 되는 것입니다.


● B 클래스

사용자 삽입 이미지

                         # Bits       1      1                       14                                  16

첫번째, 두번째 칸 : B 클래스라는 것을 알려주기 위한 비트
세번째 칸 : 네트워크 부분
네번째 칸 : 호스트 부분

으로 나눌 수 있습니다. 그러므로 B클래스는 항상 '10'(10진수 128) 로 시작 되어야 하고 네트워크 부분의 비트는 14개 호스트 부분의 비트수는 16개로 A 클래스보다 적은 수의 호스트수를 가진 클래스 입니다. B클래스를 알리기 위한 비트수 이외에도 네트워크 부분을 나타내는 비트수가 14자리나 되어 있기 때문에 B클래스의 네트워크 번호는 128.1~191.254 까지 입니다.

B클래스의 가장작은 수는 1000 0000.0000 0000.0000 0000.0000 0000 ~10진수~> 128.0.0.0
B클래스의 가장큰 수는 1011 1111.1111 1111.1111 1111.1111 1111 ~10진수~> 191.255.255.255

여기서 128.0 은 네트워크 주소를 191.255 는 브로드 캐스트 주소이기 떄문에 제외한 128.1~191.254 를 네트워크 부분의 갖습니다.


● C 클래스

사용자 삽입 이미지

                      # Bits     1       1       1                  21                                  8

첫번째, 두번째, 세번째 칸 : C 클래스라는 것을 알려주기 위한 비트
네번째 칸 : 네트워크 부분
다섯번째 칸 : 호스트 부분

으로 나눌수 있습니다. 가장 적은 호스트 수를 가지고 있는 클래스 이고 네트워크 부분은 192.0.1~223.255.254 까지 입니다.

C클래스의 가장작은 수는 1100 0000.0000 0000.0000 0000.0000 0000 ~10진수~> 192.0.0.0
C클래스의 가장큰 수는 1101 1111.1111 1111.1111 1111.1111 1111 ~10진수~> 223.255.255.255


출처 : http://bongsnet.tistory.com/15

 



___________________________________________________________________________________________


multicast ; 멀티캐스트

인터넷의 전송 방식은 전송에 참여하는 송신자와 수신자 관점에서 나누어 유니캐스트, 브로드캐스트, 멀티캐스트로 구분할 수 있다.

유니캐스트 전송 방식은 하나의 송신자가 다른 하나의 수신자로 데이터를 전송하는 방식으로 일반적인 인터넷 응용프로그램이 모두 유니캐스트 방식을 사용하고 있다. 브로드캐스트 전송방식은 하나의 송신자가 같은 서브네트웍 상의 모든 수신자에게 데이터를 전송하는 방식이다. 반면 멀티캐스트 전송방식은 하나 이상의 송신자들이 특정한 하나 이상의 수신자들에게 데이터를 전송하는 방식으로 인터넷 화상 회의 등의 응용에서 사용한다.

그룹 통신을 위하여 다중 수신자들에게 동일한 데이터를 전송하고자 할 경우 유니캐스트 전송방식을 이용한다면 전송하고자 하는 데이터 패킷을 다수의 수신자에게 각각 여러 번 전송해야 하며, 이러한 동일한 패킷의 중복전송으로 인해 네트웍 효율이 저하된다. 또한 수신자 수가 증가할 경우 이러한 문제점은 더 커지게 된다.

반면 멀티캐스트 전송이 지원되면 송신자는 여러 수신자에게 한 번에 메시지가 전송되도록 하여, 데이터의 중복전송으로 인한 네트웍 자원 낭비를 최소화할 수 있게 된다.

멀티캐스트 전송이 일반적인 유니캐스트 인터넷 응용 분야와 다른 점은 우선 그 전송 패킷에 있다. 일반적으로 TCP/IP 상의 인터넷 응용 프로그램은 데이터의 송신자가 이를 수신할 수신자의 인터넷 주소를 전송 패킷의 헤더에 표시해 패킷을 전송한다. 그러나 멀티캐스트 전송을 위해서는 헤더에 수신자의 주소 대신 수신자들이 참여하고 있는 그룹 주소를 표시하여 패킷을 전송한다.

멀티캐스트 전송을 위한 그룹 주소는 D-class IP 주소 (224.0.0.0∼239.255.255.255)로 전세계 개개의 인터넷 호스트를 나타내는 A, B, C-class IP 주소와는 달리 실제의 호스트를 나타내는 주소가 아니며, 그룹 주소를 갖는 멀티캐스트 패킷을 전송받은 수신자는 자신이 패킷의 그룹에 속해있는 가를 판단해 패킷의 수용여부를 결정하게 된다.

그러나 현재 인터넷상의 라우터들이 대부분 유니캐스트만을 지원하기 때문에 멀티캐스트 패킷을 전송하기 위하여서는 멀티캐스트 라우터 사이에 터널링이라는 개념을 사용하여 캡슐화된 패킷을 전송한다. 즉 멀티캐스트 주소를 가진 데이터 패킷 헤더 앞에 멀티캐스트 라우터간에 설정된 터널의 양 끝단의 IP 주소를 덧붙여 라우팅을 함으로써 멀티캐스트를 지원하지 않는 일반 라우터들을 거칠 때 기존의 유니캐스트 패킷과 같은 방법으로 라우팅되어 최종적으로 터널의 종착지로 전송될 수 있게 하는 것이다.


출처 : http://terms.co.kr/multicast.htm



원자적 연산이 가능한 연산자가 있어야 임계영역이 구축 가능하다..

실험 결과 변수++ 혹은 변수-- 은 원자적 연산이었다.

뮤텍스나 세마포 혹은 크리티컬섹션을 라이브러리나 이미 구현된 것을 사용하는 것이 아닌 자신이 만약에 구현해야한다.

음.. 과제나 모 그런것

그때는 ++ , -- 연산을 이용하여 구현하기 바랍니다.

혹은 원자적 연산이 가능한 또다른 무언가를 이용하기 바랍니다.


ps . 결국 나한테 하는 말이구나..
Eclipse 자주 쓰는 단축키 -

- Eclipse 자주 쓰는 단축키 -

 

----- 실행 -----

Ctrl + F11 : 바로 전에 실행했던 클래스 실행

 

----- 소스 네비게이션 -----

Ctrl + 마우스커서(혹은 F3) : 클래스나 메소드 혹은 멤버를 상세하게 검색하고자 할때

Alt + Left, Alt + Right : 이후, 이전

Ctrl + O : 해당 소스의 메소드 리스트를 확인하려 할때

F4 : 클래스명을 선택하고 누르면 해당 클래스의 Hierarchy 를 볼 수 있다.


Alt + <-(->) : 이전(다음) 작업 화면

 

----- 문자열 찾기 -----

Ctrl + K : 찾고자 하는 문자열을 블럭으로 설정한 후 키를 누른다.

Ctrl + Shift + K : 역으로 찾고자 하는 문자열을 찾아감.

Ctrl + J : 입력하면서 찾을 수 있음.

Ctrl + Shift + J : 입력하면서 거꾸로 찾아갈 수 있음.

Ctrl + F : 기본적으로 찾기

 

----- 소스 편집 -----

Ctrl + Space : 입력 보조장치(Content Assistance) 강제 호출 => 입력하는 도중엔 언제라도 강제 호출 가능하다.

F2 : 컴파일 에러의 빨간줄에 커서를 갖져다가 이 키를 누르면 에러의 원인에 대한 힌트를 제공한다.

Ctrl + L : 원하는 소스 라인으로 이동

   로컬 히스토리 기능을 이용하면 이전에 편집했던 내용으로 변환이 가능하다.

Ctrl + Shift + Space : 메소드의 가로안에 커서를 놓고 이 키를 누르면 파라미터 타입 힌트를 볼 수 있다.

Ctrl + D : 한줄 삭제

Ctrl + W : 파일 닫기

Ctrl + I : 들여쓰기 자동 수정

Ctrl + Shift + / : 블록 주석(/* */)

Ctrl + Shift + \ : 블록 주석 제거

Ctrl + / 여러줄이 한꺼번에 주석처리됨. 주석 해제하려면 반대로 하면 된다.

Alt + Up(Down) : 위(아래)줄과 바꾸기

Alt + Shift + 방향키 : 블록 선택하기

Ctrl + Shift + Space : 메소드의 파라메터 목록 보기

Ctrl + Shift + O : 자동으로 import 하기

Ctrl + Shift + F4 : 열린 파일 모두 닫기

Ctrl + M : 전체화면 토글

Ctrl + Alt + Up(Down) : 한줄(블럭) 복사

Ctrl + , or . : 다음 annotation(에러, 워닝, 북마크 가능)으로 점프

Ctrl + 1 : 퀵 픽스

F3 : 선언된 변수로 이동, 메소드 정의부로 이동

Ctrl + T : 하이어라키 �b업 창 띄우기(인터페이스 구현 클래스간 이동시 편리)

Ctrl + O : 메소드나 필드 이동하기

Ctrl + F6 : 창간 전환, UltraEdit  Editplus  Ctrl + Tab 과 같은 기능

 

----- 템플릿 사용 -----

sysout 입력한 후 Ctrl + Space 하면 System.out.println(); 으로 바뀐다.

try 입력한 후 Ctrl + Space 하면 try-catch 문이 완성된다.

for 입력한 후 Ctrl + Space 하면 여러가지 for 문을 완성할 수 있다.

템플릿을 수정하거나 추가하려면 환경설정/자바/편집기/템플릿 에서 할 수 있다.

 

----- 메소드 쉽게 생성하기 -----

클래스의 멤버를 일단 먼저 생성한다.

override 메소드를 구현하려면, 소스->메소드대체/구현 에서 해당 메소드를 체크한다.

기타 클래스의 멤버가 클래스의 오브젝트라면, 소스->위임메소드 생성에서 메소드를 선택한다.

 

----- organize import -----

자바파일을 여러개 선택한 후 소스->가져오기 체계화 해주면 모두 적용된다.

 

----- 소스 코드 형식 및 공통 주석 설정 -----

환경설정 -> 자바 -> 코드 스타일 -> 코드 포멧터 -> 가져오기 -> 프로파일.xml 을 불러다가 쓰면 된다.

또한 다수의 자바파일에 프로파일을 적용하려면 패키지 탐색기에서 패키지를 선택한 후 소스 -> 형식화를 선택하면 된다.

환경설정 -> 자바 -> 코드 스타일 -> 코드 템플리트 -> 가져오기 -> 템플리트.xml 을 불러다가 쓰면 된다.

 

----- 에디터 변환 -----

에디터가 여러 파일을 열어서 작업중일때 Ctrl + F6 키를 누르면 여러파일명이 나오고 F6키를 계속 누르면 아래로

Ctrl + Shift + F6 키를 누르면 위로 커서가 움직인다.

Ctrl + F7 : 뷰간 전환

Ctrl + F8 : 퍼스펙티브간 전환

F12 : 에디터로 포커스 위치

 

 

 

 

 

- 이클립스 자주쓰는 단축키 -

 

Ctrl + / : 주석 처리 - 한 라인/블록에 대해 주석 처리 (추가 및 제거)

Ctrl + L : 특정 라인으로 이동

Ctrl + F6 : Editor 창간의 이동

Ctrl + F7 : View 이동 메뉴

Ctrl + F8 : Prespectives 이동 메뉴

Ctrl + D : 한라인 삭제 - 커서가 위치한 라인 전체를 삭제 한다.

Ctrl + J : Incremental find 이클립스 하단 상태 표시줄에 Incremental find 라고 표시되어 한 글자자씩 누를 때 마다 코드내의 일치하는 문자열로 이동 , 다시 Ctrl + J 를 누르면 그 문자열과 일치 하는 부분을 위/아래 방향키로 탐색이 가능하다.

Ctrl + N : 새로운 파일 / 프로젝트 생성

Ctrl + 1 (빠른교정) - 문 맥에 맞게 소스 교정을 도와 준다. 변수를 선언하지 않고 썼을경우 빨간색 에러 표시되는데 이 단축키를 적용하면 변수에 맞는 선언이 추가 되도록 메뉴가 나타난다.

Ctrl + 0 : 클래스 구조를 트리로 보기

Ctrl + Space :  Cotent Assist - 소스 구문에서 사용 가능한 메소드, 멤버들의 리스트 메뉴를 보여준다.

Ctrl + PageUp , Ctrl + PageDown : Edit 창 좌우 이동 - Edit 창이 여러개 띄워져 있을경우 Edit 창간의 이동 한다.

Ctrl + Shift + Down : 클래스 내에서 다음 멤버로 이동

Ctrl + Shift + M : 해당 객체의 Import 문을 자동 생성 - import 추가 할 객체에 커서를 위치 시키고 단축키를 누르면 자동적으로 import 문이 생성

Ctrl + Shift + O : import 문을 자동 생성 - 전체 소스 구문에서 import 안된 클래스의 import 문을 생성해 준다.

Ctrl + Shift + G : 해당 메서드 / 필드를 쓰이는 곳을 표시 - View 영역에 Search 탭에 해당 메서드 / 필드를 사용하는 클래스를 표시 해준다.

Alt + Shift + R : Refactoring (이름변경) - Refactoing 으로 전체 소스에서 이름변경에 의한 참조 정보를 변경해 준다.

F3 : 선언 위치로 이동

F11 : 디버깅 시작

F8 : 디버깅 계속

F6 : 디버깅 한줄씩 실행(step over)

F5 : 디버깅 한줄씩 실행 함수 내부로 들어감 (step into)

F12 : Editor 창으로 이동 (Debugging 등 자동적으로 포커스가 이동 됐을경우 편리)

Alt + Up , Alt + Down : 줄 바꿈 - 해당 라인을 위 / 아래로 이동 시킨다.

Alt + Shift + S : Source Menu - 소스메뉴 (Import 추가 , Comment 추가 , 각종 Generator 메뉴) 가 나타난다.

Alt + Shift + Up : 블록설정 - 소스 코드를 블록 단위로 설정해 준다.

Alt + Shift + Down : 블록해제 - 소스 코드를 블록 단위로 해제한다.

Alt + Shift + J : 주석 생성 - 해당 메서드/클래스에 대한 주석을 템플릿을 생성해 준다.

sysout + (Ctrl + Space) : System.out.println() 문장 삽입 - 코드 템플릿을 이용해서 소스 구문을 추가

(Windows -> Preferences -> JAVA -> Editor -> Templates 에서 자주 쓰는 소스 구문을 추가시키면 <템플릿 이름> + (Ctrl + Space) 로 소스 문장을 완성 시킬 수 있다.)

Alt + Shift + Z : Surround With 메뉴 - try / catch 문이나 for , do , while 등을 해당 블록에 감싸주는 메뉴가 나타난다.

Ctrl + Shift + F : 코드 포맷팅 - 코드 내용을 문법 템플릿에 맞게 포맷팅(들여쓰기) 해준다.

Ctrl + Alt + Down: 한줄 복사후 아래에 복사 넣기 - Copy&Paste 대체하는 단축키. 커서가 위치한 라인을 복사해 밑줄에 생성해 준다.

Ctrl + Shift +X : 대문자로 변환

Ctrl + Shift + Y : 소문자로 변환

Ctrl + Shift + L : 모든 단축키의 내용을 표시해준다.

Ctrl + Shift + B : 현재 커서 라인에 Break point 설정

Ctrl + Shift + T : 클래스 찾기

출처 : http://littletrue.egloos.com/3987863


현재 c문법 (ANSI C)

int sum(int a, int b)

{

int sum = a+ b ;

return 1 ;

}








과거 c문법 (K&R)

int sum( a, b)

int a ;

int b ;

{

int sum = a + b ;

return 1 ;

}


어느 소스에 K&R 스타일로 되있기에 처음에는 당황했다.
검색 결과 이런 스타일이 과거에 있었다고 한다. 신기하다.


리눅스에서 안드로이드 소스를 다운 받기 위해

repo init -u git://android.git.kernel.org/platform/manifest.git

실행시...


....

android.git.kernel.org[0: x.x.x.x]: errno=Connection refused

android.git.kernel.org[0: x.x.x.x]: errno=Connection refused

....


등의 에러가 뜬다면..


git 프로그램이 사용하는 포트가 외부 방화벽에 위해 막혀 있는 경우일 가능성이 높다..

http 프로그램이 사용하는 공용포트를 통해 안드로이드 소스를 다운받을 수 있다...

(git프로그램이 사용하는 포트를 피하고 http 프로토콜이 사용하는 포트를 쓴다는 것이다.

다행히 git프로그램이은 통신 프로토콜에서 독창적이지 않다는 거겠다.)


일단


1)$ gedit ~/bin/repo

을 실행하면 편집창이 뜨고 여기서 git://을 http://로 바꾼다.
REPO_URL=’git://android.git.kernel.org/tools/repo.git’ ====> http://


2) 다음 git파일을 다시 다운받는다. 잘 될 것이다. 각 설정 알아서 선택.

repo init -u http://android.git.kernel.org/platform/manifest.git


3) 곧바로 repo sync하면 또 에러가 난다. 이 부분을 수정해야 한다.

$ gedit .repo/manifest.xml 을 실행하고

에서 git:// android.git.kernel.org” ===> http://... 수정


4) 마지막으로

$gedit .repo/repo/repo 실행하고

“git:// android.git.kernel.org/tools/repo.git” ===> http://... 수정

5) repo sync 명령 실행해서 소스를 다운받는다.

출처 : http://blog.daum.net/camanse/42
참고 : http://thanhpt25.wordpress.com/2010/11/05/android-first-step-download-and-build/


이 이클립스 오류는

구글 맵 때문에 api key 인증 받으려다 보니까 생겼다.

외국 사이트에서 해결 방법을 찾았다.


  1. DOS: del c:\user\dad\.android\debug.keystore

  2. ECLIPSE: In Project, Clean the project. Close Eclipse. Re-open Eclipse.

  3. ECLIPSE: Start the Emulator. Remove the Application from the emulator.

    1. c:\users\[사용자이름]\.android/debug.keystore 를 삭제
    2. 이클립스 다시 실행
    3. 프로젝트 하나 실행 시킨다.

    이러면 끝.. 결국 debuf.keystore 만 지우면 된다는 뜻



    출저 : http://stackoverflow.com/questions/2194808/debug-certificate-expired-error-in-eclipse-android-plugins


NonBlocking. 단순히 블락되지 않음.

1000Byte 를 Operation 할 경우, 0~1000Byte 까지 상황에 따라 임의로 Operate 하고 리턴함.

원하는 작업을 다 끝내기 위해선 루프를 돌며 완료하는 과정이 필요



Overlapped. 논블로킹에 All or Nothing 의 개념을 추가.

Overlapped 에서는 Operation 을 할 경우, 반드시 끝나던가 실패하던가 둘 중 하나

참고 : http://kltp.kldp.net/eunjea/ssh/x87.html 



* 사용자의 이름은 user 라 하고 접속하고자 하는 서버의 사용자명은 test라고 한다.

다시 말해 user@user 라는 사용자가 test@123.456.789.000 에 접속하려고 할때

ssh 키를 생성해서 비번을 사용 안하고 접속 하는 방법을 말하는 것이다.

(용어의 정의)

user 의 홈 (예) /home/user

test 의 홈 (예) /home/test

> => 뒤에 오는 명령어를 실행

1. 로컬 ssh RSA 키의 생성

1) user의 홈에서 >cd .ssh/ 를 한다.

id_rsa 파일이 있음을 확인하다 (내용이 궁금하면 >cat id_rsa )

2) ssh-keygen -t rsa 명령으로 id_rsa.pub을 생성한다.

(id_rsa값을 기준으로 public key 값을 생성하여 저장한 것이 id_rsa.pub 이다.)

3) vim id_rsa.pub 을 실행해서 안에 있는 내용을 전부 복사한다.

2. 원격서버에 RSA 키 값 설정

1) ssh test@123.456.789.000 을 실행하여 test 계정에 접속한다.

2) test의 홈에서 >cd .ssh/ 실행

3) vim authorized_keys 를 실행(파일이 있으면 아래에 내용을 덧붙이고 없다면 파일을 생성한다)

4) 1.3)에서 복사한 내용을 붙여 넣는다. :wq 로 저장

3. 자동접속 여부 확인

1) >exit 해서 원래 user 계정으로 돌아와서

2) >ssh test@123.456.789.000 을 실행해본다.

3) passwd 입력없이 로그인되는 모습을 확인할 수 있다.




대처법 :
클라이언트 쪽에서  Agent admitted failure to sign using the key. 이런 메세지가 나온다면

접속하려는 서버의 ssh-agent 가 아직 메모리에 상주하지 못했기 때문이다.

이때는 서버에 접속해서 # eval $(ssh-agent) 를 실행시켜주면 된다.

그래도 안된다면 # ssh-add 를 실행시키도록 한다.




커널 소스를 보다보면 asmlinkage로 선언된 함수들을 볼 수 있다.
asmlinkage는 어셈블리 코드에서 직접 호출(링크)할 수 있다는 의미이며
커널 소스의 <include/linux/linkage.h>에 다음과 같이 정의되어 있다.

#include <linux/config.h>
#include <asm/linkage.h>

#ifdef __cplusplus
#define CPP_ASMLINKAGE extern "C"
#else
#define CPP_ASMLINKAGE
#endif

#ifndef asmlinkage
#define asmlinkage CPP_ASMLINKAGE
#endif

...

그렇다면 어셈블리 코드에서 직접 호출할 수 있다는 것은 무엇을 의미할까?
일반적으로 C 함수는 어셈블리 코드에서 별 어려움없이 호출할 수 있지만
함수의 인자를 넘기거나 리턴값을 받는 부분 등의 호출 규약이 필요하다.

레지스터에 여유가 있는 ARM이나 MIPS 등의 아키텍처에서는
함수의 인자를 넘길 때 특정 레지스터를 사용하도록 호출 규약이 정의되어 있지만,
그렇지 못한 x86 아키텍처에서는 때에 따라 레지스터, 스택 혹은 별도의 메모리 영역에
함수의 인자를 저장하여 넘길 수 있도록 지원한다.

당연히 인자를 레지스터에 저장하여 넘기는 방식이 빠르기 때문에 (fastcall)
최적화 옵션을 켜고 컴파일하는 경우 인자를 레지스터를 통해 전달하도록
함수의 호출부와 구현부를 변경해 버릴 수 있다. (일반적인 최적화 방법)
이 경우 GCC를 통해 자동 생성되는 코드는 적절히 변환되므로 문제가 없을테지만
직접 작성한 어셈블리 코드에서 함수를 호출하는 경우 문제가 발생하게 된다.

이 경우를 방지하기 위해 어셈블리 코드와 링크되는 함수는
인자를 (레지스터를 이용하지 않고) 스택을 이용해서 전달하도록
선언하는 데, 이 때 asmlinkage가 사용된다.

위의 코드에서 <asm/linkage.h> 파일을 #include 하고 있는 것에 주의하자.
대부분의 아키텍처에서 이 파일은 asmlinkage를 정의하지 않지만
i386에서는 다음과 같이 정의한다.

#define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0)))
#define FASTCALL(x) x __attribute__((regparm(3)))
#define fastcall __attribute__((regparm(3)))

regparm 속성은 레지스터를 이용하여 전달한 인자의 수를 지정한다.
asmlinkage로 선언된 경우 모두 스택을 이용하고 (레지스터로 0개의 인자 전달)
fastcall로 선언된 경우 최대 3개의 인자를 레지스터로 전달한다.
(이 경우 EAX, EDX, ECX 레지스터를 이용하며, 인자는 정수형이어야 한다.)
출처 : http://studyfoss.egloos.com/4951809

이클립스에 VisualEditor란 플러그인이 있다. 

이 플러그인은 자바 GUI를 비주얼적으로 작성가능케한다.

비주얼베이직이나 mfc같이 컴포넌트를 끌어다 놓는 방식으로 ui를 작성할 수 있다.


설치법

1. 이클립스 help -> install new software 를 클릭
2. 새창이 띄워지면 Work with란 레이블이 있다. 그 옆에 주소를 적을수 있는 공간이 있다.
3. 그곳에 http://download.eclipse.org/tools/ve/updates/1.5.0/ 를 적고 엔터를 누르면 밑에 Tools VE가 보일것이다.
4. Tools VE 를 체크 표시하고 next 로 진행하면 설치가 된다.

사용법

file -> new 의 other 을 클릭하고 java 에 Visual Class 가 생긴것을 볼수 있다.

이것을 클릭해서 Class를 만들게 되면 비주얼 환경에서 자바 GUI 프로그래밍을 할 수 있다...


(자바 GUI를 많이 프로그래밍하지는 않지만.. 프로그램 만들때 레이아웃 때문에 고생한걸 생각하면.. 왜 이제 알았을까..)

ERROR:
ORA-28009: connection as SYS should be as SYSDBA or SYSOPER

이런 에러 출력시

as SYSDBA 란 옵션이 필요하다

예) sqlplus 아이뒤/비번 as SYSDBA

라고 입력해야 관리자 아이디를 SYSDBA 권한으로 접속할수 있다.

+ Recent posts