336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.
APK003 print를 잘 쓰자
==============================================

1. 개요

이 문서는 ESP-NS에서 동작하는 응용 프로그램에서
printf 를 쓰는 방법에 대한 소개 입니다.

작성자 : 유영창
frog@falinux.com
작성일 : 2004년 9월 10일
수정일 :

관련된 ADK( Application Developer Kit ) 디렉토리

adk/sample/printf

2. 최강의 디버거 printf

응용 프로그램을 작성하는 과정에 반드시 수반되는 것이
디버깅입니다. 이 과정은 프로그래머에게는 숙명입니다.
이걸 피해갈 사람은 없읍니다.

윈도우 프로그래머라면 통합 환경에서 제공하는 디버깅기능을
즐겨 사용하게 됩니다.

이런 분들이 임베디드 리눅스에서 동작하는 프로그램을 디버깅
하면 갑갑함을 느낍니다.

왜냐?

임베디드 리눅스에서 사용할만한 통합환경이 없다는 것이
가장 큰 이유입니다

그렇다면 리눅스에는 쓸만한 디버거가 없을까요?

있읍니다 그것도 엄청 막강한 gdb라는 툴이 있읍니다.

그러나

제 주위에서 이 프로그램을 사용하는 사람 본적이
별로 없읍니다.

왜냐하면 준비하는데 엄청난(?) 작업이 필요하기 때문입니다.
특히 저같이 게으른 사람에게는 gdb를 이용해서 작업하는
과정은 무척 어려운 일입니다.

라인 명령을 사용해야하고 디버깅을 위한 준비작업 또한
만만치 않기 때문입니다.

그래서 저는 printf 라는 막강한 디버거를 사용합니다.

사실 임베디드 시스템에서 printf 함수는 목적하는 기능구현을
위해서 사용할 필요가 없는 함수입니다.

뭐 .... PC 리눅스에서도 마찬가지죠..

하지만

이 printf 함수 만큼 즐겨 사용하는 함수가 없읍니다.

주로 디버깅을 위해서 사용합니다.

이 printf 디버거는 무척 강력합니다.

일단 준비할 것이 없읍니다

그냥 printf 만 사용하면 됩니다.

그리고 내가 원하는 모든 변수값들을 찍어 볼수 있읍니다.
내가 원하는 함수의 문장을 통과하는지를 관찰할수 있읍니다.

디버깅이라는 것이 이게 다 아니겠읍니까?

리눅스 프로그램머들은 고수가 될수록 이 printf 함수를
자유자재로 사용합니다.

저 스스로도 고수라고 칭하므로 당근 이 printf 함수를
아주 적절히(?) 절묘하게(?) 사용합니다.
이건 고수들만의 노하우도 됩니다. ( 퍽~~ ㅜㅜ )

그런데 이 printf 를 그냥 사용하는 것은 조금 불편합니다.

그래서 조금 변경해서 사용하는데 이것을 소개할까 합니다.
그리고 더불어 주의점도요...

3. printf함수도 시간을 빼앗아 간다.

printf 를 그냥 사용해도 되지만 디버깅 단계에서는 유용하겠지만
나중에는 수많은 메세지들이 콘솔에 난무하는 엄청난 혼란을
발생합니다. ( 당해본 사람만 압니다.)

그래서 고수(?)들은 이 printf 를 그냥사용하지 않고 매크로 함수로
변형해서 사용합니다.

간단하게 소개 하면 이렇게 어딘가에 선언을 합니다.

//#define NDEBUG

#ifndef NDEBUG
#define dp(fmt,args...) printf( fmt, ## args )
#define dlp(fmt,args...) printf( "[%s %d]" fmt, __FILE__,__LINE__, ## args )
#else
#define dp(fmt,args...)
#define dlp(fmt,args...)
#endif


이것은 NDEBUG 라는 것이 선언되어 있지 않으면
dp 라는 것은 printf 함수로 대치 됩니다.
( dlp 라는 것은 조금 나중에 설명하겠읍니다. )

만약 NDEBUG 라는것이 선언되면 printf 는 아무것도 하지 않고
프로그램 소스에서 제거 됩니다.

예를 들어

printf( "hello world\n" );

이라고 쓰는 것은

dp( "hello world\n" );

라고 쓰면 됩니다.

#define NDEBUG 라는 문장이 없으면
위 문장들은 출력을 발생하게 됩니다.

그러나

#define NDEBUG 를 선언하게 되면

dp( "hello world\n" );

는 아무런 일도 하지 않습니다. 더구나 컴파일러의 최적화에 의해서
실행코드의 크기도 작아 먹지 않습니다.

위에서 소개한 dp 문은 보통 전체 소스 파일들이 사용하는 공통 헤더파일에
정의해 써 놓고 사용하는 것이 좋습니다.

평소에는 dp 문을 이용하여 출력을 하다가

NDEBUG 라는 문자열만 사용하면 싹~ 없어지기 때문에 나중에 한꺼번에
출력이 안될수도 있기 때문에 추척 편리한 함수입니다.

하나의 소스파일에서 메세지 출력을 없애고 싶다면
해당 소스파일에 위 정의문의 바로 위나 위 정의문을 포함한 헤더파일을
선언하는 #include 문 앞에 NDEBUG 라는 문자열을 정의하면 됩니다.

정말 정말 편리한 기능입니다.

만약 프로그램 전체에서 dp를 사용한 문자열의 출력을 제거하고 싶다면
그냥 컴파일 옵션에 -DNDEBUG 라는 것만 추가 하면됩니다.

APK 에 있는 샘플에 소개한 Makefile을 사용한다면
Makefile 에 있는

CFLAGS += -Wall -O2 -g



CFLAGS += -Wall -O2 -g -DNDEBUG

로 바꾸면 됩니다.

4. printf함수를 이용한 위치 추적

혹시 다음과 같은 문장의 의미를 여러분은 아시는 지 모르겠읍니다.

printf( "%s %s %d\n", __FILE__, __FUNCTION__, __LINE__ );

이것은 이 문장이 적혀진 라인을 포함하는 파일명과 함수명 그리고
파일의 라인번호를 출력하게 합니다.

그래서 이것을 이용해서 dlp라는 함수를 선언합니다.

dp는 단순히 어떤 메세지나 값을 표출하는데 사용한다면
dlp는 해당 메세지가 표출된 위치를 함께 표출하기 위해서 사용합니다.

5. \r 을 출력하는 문자열 라인의 앞에 추가 하자!

초기에 보드에 프로그램을 작성 하다 보면 디버깅을 위한 메세지를
출력하면서 동작상태를 관찰하게 됩니다.

그런데 응용 프로그램을 자동으로 실행하게 했다면 로긴이 안된 상태이기
때문에 문자열의 '\n' 문자 때문에 다음과 같은 현상이 발생합니다.

message line 1
message line 2
message line 3

원래는 줄 앞에 나란히 정렬해야 하는데 삐뚤 삐뚤하게 출력되기 때문에
애써 예쁘게 출력하도록 한 내용이 보기 어렵게 됩니다.

그래서 한 라인의 시작 문자열 맨 앞에서는 '\r' 문자를 사용하는 것이 좋습니다.

예를 들어

printf( "message line 1\n" );
printf( "message line 2\n" );
printf( "message line 3\n" );

이라고 한다면 이것을 다음과 같이 고쳐 주어야 합니다.

printf( "\rmessage line 1\n" );
printf( "\rmessage line 2\n" );
printf( "\rmessage line 3\n" );

6. \n을 사용하기 전까지는 화면에 출력되지 않는다.

printf 문장을 사용해서 다음과 같이 특정 변수명값을 추적한다고 합시다.

while(1)
{
:
printf( "%d ", test_v );
:
}

이렇게 하고 출력이 나올걸 기대하면 아마도 전혀 의도하지 않는 현상이
발생할겁니다.

리눅스에서 printf 문은 '\n' 을 만나기 전까지는 출력 처리가 되지 않는
다는 점을 기억합시다.!!!!

왜 이렇게 될까요?

그것은 여러 프로세스들이 서로 출력을 할때 보기 편하라는 의미가 담겨
있읍니다

A 프로그램도 출력도 하고 B 프로그램도 출력을 하고 있다면 아마도
먼저 보낸 순서대로 출력이 되어야 할겁니다. 그러면 서로 짬봉이
되는 바람에 무슨 내용인지 알수가 없죠...

그래서 '\n'을 먼저 출력하는 프로그램의 출력 내용을 표출하는 것입니다.

그래서 출력 결과를 보시고자 한다면 항상 출력하고자 하는 내용의 마지막에는
'\n'을 꼭 추가하시기 바랍니다.

7. printf 는 실제로 시리얼로 출력하는 것이다.

ESP 보드는 printf 가 메인 콘솔에서 본다면 시리얼로 데이터가 전송되는 것입니다.
메인 콘솔의 속도가 115200 으로 되어 있지만 이 속도가 그렇게 빠르지 않다는 점을
명심하시기 바랍니다.

나중에 printf 가 블럭 되기도 하고 아주 빠른 처리를 요구하는 부분에서 printf를
남발하면 큰 코 다치게 됩니다.

특히 printf 는 그 처리가 무척 복작한 함수입니다. 그래서 한번만 호출해도
엄청난 수행시간을 필요로 합니다.

그래서 가끔 아주 간단한 지연이 필요한 경우에는 이 printf 함수를 사용하기도
한다는 점 기억하시기 바랍니다. 그만큼 처리 속도를 잡아 먹는 다는 이야기 입니다.

'Programming > Linux' 카테고리의 다른 글

Linux find grep 명령사용하기  (0) 2008.06.24
Fedora8사전에서 Microsoft를 검색하면...  (0) 2008.05.26
리눅스 디렉토리  (0) 2008.05.21
Data Types  (0) 2008.04.03
유닉스/리눅스 명령어 레퍼런스  (0) 2008.03.26
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.
■ 리눅스 디렉토리 구조

□ / (root)
- 마운트 되는 리눅스 파일 시스템이 있는 최상위 디렉토리
- 시스템의 근간을 이루는 가장 중요한 디렉토리
- 파티션 설정 시 반드시 존재하여야 함
- 절대경로의 기준이 되는 디렉토리
    ※ 절대경로 - / 디렉토리 기준   예) /usr/local
       상대경로 - 현재 작업 디렉토리 기준 예) ./local

□ /bin
- 리눅스의 기본 명령어(binary)들이 들어있는 디렉토리
- 시스템을 운영하는데 기본적인 명령어들이 들어 있음.

□ /sbin
- 시스템 관리에 관련된 실행 명령어들이 들어있는 디렉토리
- 시스템 점검 및 복구 명령, 시스템 초기 및 종료 명령 등 시스템 관리에
   관련된 실행파일들 존재.

□ /lib
- 프로그램들이 의존하고 있는 라이브러리 파일들 존재.
- /lib/modules : 커널 모듈 파일들 존재.
- 대부분의 라이브러리들은 링크로 연결되어 있음.

□ /proc
- 시스템에 대한 정보를 제공하는 가상 파일 시스템.
- 커널의 어떤 기능을 제어할 수 있는 역할을 가지고 있음.
- 대부분 읽기 전용이나, 일부 파일중에는 쓰기가 가능한 파일이 존재
   하는데 이러한 파일들에 특정 값을 지정하면 커널 기능이 변하게 됨.
- 이 디렉토리 내에 있는 파일을 cat 명령을 이용하여 보면 시스템 정보를
   확인 할 수 있음.
   예) 인터럽트 정보 확인 ---> cat /proc/interrupts

□ /etc
- 시스템 환경 설정 파일이 있는 디렉토리
- 네트워크 관련 설정파일, 사용자 정보 및 암호정보, 파일 시스템 정보,
   보안파일, 시스템 초기화 파일등 중요 설정 파일들의 위치한 디렉토리
- /etc/CORBA : Common Object Request Broker Architecture (COBRA)에
                관한 파일이 들어있음.
- /etc/X11 : 엑스 윈도우 설정에 관련된 파일들이 있음.
- /etc/cron.d : crontab 명령의 설정파일이 있음.
- /etc/cron.daily : 매일 작동하게 하는 crontab 스크립트 파일이 존재.
- /etc/gnome : GTK+ 정의파일들이 있음.
- /etc/httpd : 아파치 웹 서버의 설정 및 로그파일이 있음.
- /etc/logrotate.d : logrotate 설정 파일들이 있음.
- /etc/mail : 센드메일과 관련된 파일이 있음.
- /etc/ppp : ppp 설정에 관련된 파일들이 있음.
- /etc/profile.d : 쉘 로그인 하여 프로파일의 실행되는 스크립트에
                    대한 정의가 있음.
- /etc/rc.d : 시스템 초기화와 관련된 스크립트가 존재.
- /etc/samba : 삼바에 관련된 파일들이 있음.
- /etc/security : 터미널 보안에 관련된 설정이 있음.
- /etc/skel : 새로운 사용자를 추가할 때 자동적으로 생성되는 디렉토리와
               파일이 있음.
- /etc/squid : squid 프록시 서버에 관련된 파일이 있음.
- /etc/ssh : secure shell 설정 파일이 있음
- /etc/sysconfig : 시스템과 네트워크 설정을 담고 있음.
- /etc/xinetd.d : 슈퍼데몬 xinetd.d의 서비스 영역을 설정하는 디렉토리.

□ /var
- 가변 자료 저장 디렉토리
- 시스템 운영중에 시스템 자료 데이터가 변경될 때 변경된 자료들이
   저장되는 곳.
- 주로 시스템 작동기록(log)들을 저장.
- /var/log : 시스템에 발생된 일들에 대한 기록 파일이 있음
- /var/named : 네임서버 설정 파일들 존재
- /var/spool/mail : 수신 메일을 사용자 명으로 기록하는 디렉토리

□ /usr
- 일반 사용자들을 위한 대부분의 프로그램 라이브러리 파일들이 위치.
- /usr/bin : 응용 프로그램의 실행 파일이 위치
- /usr/sbin : 주로 네트워크 관련 실행 명령어와 실행 데몬들을 많이
   포함하고 있음.
- /usr/X11R6 : X-window 시스템에 관련된 파일 존재.
- /usr/include : 기본 C 라이브러리 헤더 파일과 각종 라이브러리
   헤더파일들이 있음.
- /usr/lib : /usr/bin과 /usr/sbin에 있는 실행 바이너리를 실행하기 위한
   라이브러리 존재.
- /usr/src : 프로그램소스 및 커널 소스들이 보관되어 있는 곳.
- /usr/man : 매뉴얼 페이지가 담겨있는곳.
- /usr/local : 새로운 프로그램들이 설치되는 곳
    (windows의 Program Files 와 유사)

□ /mnt
- 다른 장치들을 마운트 할때 일반적으로 사용하는 디렉토리
- 다른 디렉토리를 사용하여도 됨.

□ /home
- 일반 사용자의 홈 디렉토리가 만들어 지는 디렉토리
- 사용자 계정을 만들면 게정과 같은 이름으로 새로운 사용자 디렉토리가
   /home 디렉토리의 하위 디렉토리로 생성됨.
예) test 사용자 추가 후 홈 디렉토리 확인하기.
root@test />$adduser test
root@test />$cd /home
root@test home>$ls

     test   <-- 디렉토리 생성

□ /boot
- 부팅에 핵심적인 커널 이미지와 부팅 정보 파일을 담고 있는 디렉토리
- /etc/lilo.conf에서 지정한 커널 부팅 이미지 파일이 들어 있으며 부팅시
   매우 중요한 디렉토리

□ /root
- 슈퍼유저(root) 사용자의 홈 디렉토리.
- / 와 /root 디렉토리는 부르는 이름은 같지만 서로 다름.

'Programming > Linux' 카테고리의 다른 글

Fedora8사전에서 Microsoft를 검색하면...  (0) 2008.05.26
printf를 잘 쓰자  (0) 2008.05.21
Data Types  (0) 2008.04.03
유닉스/리눅스 명령어 레퍼런스  (0) 2008.03.26
Man Page/sigaction  (0) 2008.03.26
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

1 Data Types

우리가 사용하는 데이터는 컴퓨터의 메모리에 연속된 비트의 나열로 저장이 된다. 이러한 비트의 나열은 컴퓨터입장에서는 문제가 안 되겠지만 인간의 입장에서는 알아보기 힘들다는 문제가 발생한다. 그래서 데이터 타입을 두어서 인간이 좀더 쉽게 사용할 수 있도록 하고 있다.

데이터 타입은 다음과 같은 특징을 가지고 있다.
  • 데이터가 어떻게 표현되고 사용 될지를 결정한다.
  • 데이터 타입에 따라 컴퓨터가 어떻게 데이터를 다룰지를 알려주다. (숫자로 다룰지 아니면 문자로 다룰지 등..)
  • 모든 값은 데이터 타입에 의해서 표현될 수 있다.

예를 들어서 메모리에 다음과 같은 비트패턴이 저장되어 있다고 가정해보자.
  0000 0000 0110 0111 
 

이 값이 어떻게 표현될까 ? 이것은 데이터 타입을 어떻게 정의하느냐에 따라 달라진다. 만약 데이터 타입을 'int로 하기로 했다면 숫자 103으로 표현될 것이다. 그러나 문자를 저장하는 char로 하기로 했다면 영문자 g로 표현이 된다.

데이터 타입은 이렇게 인간의 입장에서 컴퓨터 메모리에 저장된 데이터를 어떻게 다룰 것인지를 결정하기 위해서 사용이 된다.

아래의 코드를 실행시켜보기 바란다.
#include <stdio.h> 
 
int main(int argc, char **argv) 
{ 
  int a = 103; 
  char b = 103; 
 
  printf("%d\n", a); 
  printf("%c\n", b); 
} 
 
똑같은 103인데, 서로 다르게 출력되는걸 확인할 수 있을 것이다.

2 Primitive Data Types

인간은 매우 다양한 형태의 데이터를 다루기를 원하고, 그런일을 할 수 있는 프로그램을 만들어 낼 수 있어야 한다. 다루는 데이터의 형태가 다양하니, 데이터 타입 역시 다양하면 좋을 것이다. 그러나 컴퓨터는 매우 단순한 기계다. 쓸데없이 데이터 타입을 이것 저것 만들면, 이것을 다루는 컴퓨터 역시 달가워하지 않을 것이다. 프로그래머 역시 각 데이터 타입에 따른 고려사항이 늘어나니 권장할만한 사항이 아니다.

그래서 데이터타입을 다루어야 하는 프로그래밍 언어는 Primitive Data Type이라고 불리우는 최소한의 반드시 필요한 데이터 타입을 지원하고 있다. Primitive Data Type은 원시 데이터 타입 이라고 부르기도 한다.

각 원시 데이터 타입은 고유의 크기를 가지고 있으며, 표현할 수 있는 데이터의 한계가 정의되어 있다. 다음은 C 언어에서 지원하는 원시 데이터 타입과 크기, 데이터 범위를 보여주는 표다.

2.1 숫자형 원시 데이터 타입

숫자를 표현하기 위해서 사용되는 데이터 타입이다. 크게 정수형 데이터를 표현하기 위한 정수형 원시 데이터 타입부동소숫점형 원시 데이터 타입으로 나눌 수 있다.
  • 정수형 원시 데이터 타입
    char 1byte -128 127
    short 2byte -32768 32767
    long int 4byte 2,147,483,648 2,147,483,647
    long long int 8byte 9,223,372,036,854,775,808 9,223,372,036,854,775,807

이들 정수형 데이터 타입들은 signed비트라는 것을 가지고 있어서, 음수까지 표현할것인지를 정의할 수 있다. 음수까지 표현할 거라면 signed를 양수만 표현할거라면 unsigned를 타입의 앞에 붙여준다. 따로 붙여주지 않았다면 signed 가 붙은걸로 해석을 한다. 즉 위의 데이터 타입은 실제로는 signed char, signed short, signed long int, signed long long int와 동일하다.

unsigned를 명시하게 되면 양의 정수만 표현하게 된다. 음의 정수를 표현할 필요가 없으니 그만큼 양수 쪽으로 표현범위가 늘어날 것이다. unsigned char 이라면 255, unsigned long int 라면 4,294,967,295 가 된다.

  • 부동소숫점형 원시 데이터 타입
    float 4byte +/- 10E-37 +/- 10E38
    double 8byte +/- 10E-307 +/- 10E308

2.2 enumerated type

일반적으로 enumerated 타입은 숫자로 나열된 카테고리 같은 데이터를 만들기 위해서 사용한다. C에서는 enum을 이용해서 enumerated 타입의 데이터를 정의할 수 있다.
enum cardsuit { 
   CLUBS, 
   DIAMONDS, 
   HEARTS, 
   SPADES 
}; 
 
이제 enum 을 이루는 각각의 요소들은 숫자 0,1,2... 로 차례대로 대응되게 된다. 다음의 프로그램을 실행시켜 보자.
#include <stdio.h> 
enum cardsuit { 
  CLUBS, 
  DIAMONDS, 
  HEARTS, 
  SPACES 
}; 
int main() 
{ 
  printf("Card CLUBS is %d\n", CLUBS); 
  printf("Card DIAMONDS is %d\n", DIAMONDS); 
  printf("Card HEARTS is %d\n", HEARTS); 
  printf("Card SPACES is %d\n", SPACES); 
} 
 

다음과 같은 결과를 확인할 수 있을 것이다.
# ./enum 
Card CLUBS is 0 
Card DIAMONDS is 1 
Card HEARTS is 2 
Card SPACES is 3 
 

그렇지만 CLUBS 가 0이 아닌 다른 수로 대응되어야 할 경우도 생길 것이다. 그럴 땐, 필요한 값을 대입시켜 주면 된다. 즉 값을 명시하지 않으면 0부터 시작해서 1씩 증가하고, 값을 명시하면 명시된 값을 시작으로 1씩 증가하는 것으로 보면 된다.

문제
cardsuit를 다음과 같이 정의 했을 때, 어떤 값이 출력될지 생각해 보라.

enum cardsuit { 
  CLUBS = 1, 
  DIAMONDS, 
  HEARTS = 100, 
  SPACES 
}; 
 

2.3 Pointer type

컴퓨터는 계산을 하기 위한 기계다. 이때 계산에 사용될 모든 데이터는 일단 메모리로 읽혀져서 필요한 계산을 하게 된다. 예를 들어 하드디스크에 A 라는 문서가 있다고 가정해 보자. 이 문서를 편집하기 위한 프로그램을 가동시키면, 프로그램은 하드디스크에 있는 문서를 모두 읽어서 컴퓨터의 메모리로 불러들인 다음 필요한 일을 하게 된다. 다른 모든 연산들역시 마찬가지다.

그렇다면 문제가 발생한다. 컴퓨터에는 여러개의 프로그램이 떠 있을테니, 각각의 프로그램이 사용하는 데이터가 메모리의 여기저기 저장되어 있을 것이다. 이때 프로그램은 자신이 사용할 데이터가 메모리상의 어느 위치에 있는지 알고 있어야 한다.

이를 위해서 메모리에는 아래 그림과 같이 주소 값이 부여되어 있다.

pointer.png

프로그램은 이 기억값을 기억해서 데이터의 위치를 정확히 찾아내어서 읽어오게 되는 것이다. Pointer는 이러한 주소값을 저장하는 데이터 타입이다.

다른 데이터 타입들이 그렇듯이 pointer도 고유의 크기를 가지고 있다. pointer 데이터 타입의 크기는 4byte이다. 메모리상의 주소에는 마이너스 값이 필요가 없으므로 0 - 4,294,967,295의 숫자가 저장된다. 32bit 컴퓨터에 사용가능한 메모리의 총크기가 4Giga다 라는 얘기가 여기에서 나온다. 가리킬수 있는 숫자의 범위가 4,294,967,295 (약 4giga)이므로, 이를 초과한 영역에 저장된 데이터는 읽어올 수가 없기 때문이다.

이는 C 와 같은 프로그래밍 언어에도 그대로 적용된다. 포인터의 크기가 4byte 이니, 최대다룰 수 있는 메모리의 크기가 4Giga로 제한이 된다. 물론 여러분이 64bit 컴퓨터운영체제 그리고 컴파일러를 사용한다면 테라 byte급의 데이터를 다룰 수 있다. 64bit 컴퓨터가 대용량 데이터 처리에 유리하다는 얘기가 나오는 이유다.

포인터는 이쯤에서 끝내도록 하겠다. 포인터에 대한 자세한 내용은 따로 한장 정도를 할애해서 자세히 다루도록 하겠다.

3 type casting - 형변환

아래 프로그램을 컴파일 후 실행시켜 보자.
#include <stdio.h> 
 
int main(int argc, char **argv) 
{ 
  unsigned char ch = 'c'; 
 
  printf("%c\n", ch); 
  ch = ch+1; 
  printf("%c\n", ch); 
  ch = ch+1; 
  printf("%c\n", ch); 
} 
 
결과로 c d e 가 출력될 것이다.

이상하군. 분명히 두개는 서로 다른 데이터 타입인데, 더하기가 되는군 ?

앞서 언급했지만, 데이터형이란 표현방식에 따른 것일 뿐이다. 컴퓨터 입장에서는 모두가 비트일 뿐이다. 즉 ch+1은 컴퓨터 입장에서 다음과 같이 계산이 된다.
                               0110 0011   = 'a' 
 0000 0000 0000 0000 0000 0000 0000 0001   = '1' 
 ========================== 
 0000 0000 0110 0100   = 'b' 
 
만약 printf("%d\n" ch+1) 을 한다면, 100 이 출력될 것이다. 비트패턴을 숫자로 표현하도록 표현방식을 바꿨기 때문이다.

이렇게 모두 동일한 비트일 뿐임으로 서로 다른 타입간의 계산이 가능해진다. 그러나 이건 어디까지나 가능하다 일뿐 실제로는 의도하지 않는 다양한 문제가 발생할 수 있다.

  • 데이터타입의 크기에 따른 문제
    데이터 타입은 서로 다른 크기를 가지고 있다. 위의 코드에서 ch 에 1000을 더하면 어떻게 될까. 1099가 나오길 예상할 수 있겠지만 ch의 테이터 타입인 char는 1byte의 크기로 255까지만 표현이 가능하다. 때문에 데이터 저장공간을 초과하게 될 것이다. 실제로는 1byte의 상위 비트는 버려지게 된다. 고로 0-255까지의 값이 출력이 될것이다. 뭐.. 값이 255를 초과하지 않는 범위에서 연산을 한다면 문제가 없기는 하겠지만 실수로 문제가 발생할 소지가 다분하다.

    다른 데이터 타입끼리라도 주의해서 프로그래밍을 하면 문제 없겠지만 가능하면, 타입을 맞추어서 계산을 하는게 좋다.

  • signed bit 문제
    정수형 데이터 타입은 signed bit 를 가지고 있어서 이걸로 양수인지 음수인지를 판단하게 된다. 다음의 코드를 확인해 보자.

    #include <stdio.h> 
     
    int main(int argc, char **argv) 
    { 
      unsigned int i = 100; 
     
      if (i < -10) 
      { 
        printf("Large\n"); 
      } 
    } 
     
    상식적으로 100 은 -10보다 크기 때문에 if문의 블럭은 실행되지 않아야 겠지만, 컴파일해서 실행시켜 보면 블럭문이 실행이 되는걸 알 수 있다. 이는 i 가 unsigned 형으로 -10 을 unsigned 형으로 보고 비교를 하기 때문이다. -10이 unsigned 형이 되면 4,294,967,285 으로 표현이 된다. 이를 이해하기 위해서는 2의 보수를 통한 singed 데이터 처리에 대해서 알고 있어야 하는데, 5장 데이터와 비트문서를 읽어보기 바란다.

    이 문제를 해결하기 위해서 형변환을 수행한다. 위의 프로그램의 경우 문제를 피해가는 가장 좋은 방법은 i를 signed 형으로 선언하는게 될것이다. 그러나 불가피 하게 unsigned 형을 고집해야 할 경우가 발생한다. 그때는 casting(형변환)연산자를 통해서 형변환을 하도록 한다.

    if ((signed)i < -10) 
    { 
    ... 
    } 
     
    이제 제대로 되는걸 확인할 수 있을 것이다.

프로그램을 작성할 때는 데이터가 어디에 쓰일 것인지를 명확히 해서, 그에 맞는 데이터 타입을 지정해 줘야 한다. 그렇지만 사람이다 보니, 위에서 처럼 사소한 실수를 하기도 한다. 문제는 이런 프로그램도 문제 없이 컴파일이 된다는 것이다. 결국 프로그램이 실행하는 도중에 문제를 일으키게 될 것이다. 다행히 gcc 컴파일러는 컴파일 옵션을 통해서 저러한 문제를 사전에 잡아낼 수 있게 하고 있다. 위 프로그램을 type.c로 저장하고 아래와 같은 옵션을 주고 컴파일 해보자.
# gcc -W -Wall -o type type.c 
... 
type.c:7: warning: comparison between signed and unsigned 
... 
 
comparison between signed and unsigned와 같은 경고메시지를 출력함을 알 수 있다. 자세한 내용은 리팩토링 : 모든 경고메시지를 제거하라 문서를 읽어보기 바란다. 아직 읽기 버겁다면, 그냥 대충 저런게 있나보다 하는 수준에서 읽어두어도 도움이 될 것이다.

4 문자와 문자열 표현

데이터는 크게 문자와 숫자로 이루어져 있음을 알고 있다. 그런데 정작 문자문자열을 표현하기 위한 데이터 타입을 다룬거 같지를 않다. 이에 대해서 얘기해 보고자 한다.

C 언어에서 문자를 위한 데이터 타입으로는 char 데이터 타입을 사용한다. char 는 1byte 256의 크기를 가지는데, 1byte 문자권의 영어와 수십개의 특수문자를 충분히 표한할 수 있는바 char를 문자를 저장하기 위한 데이터 타입으로 사용하고 있다.

컴퓨터에서 표현되는 문자는 0에서 255까지의 각 크기에 대응되는 문자들이 표준으로 정의되어 있다. 각 값에 대응되는 문자는 ASCII 테이블로 정리되어 있다.

http://www.joinc.co.kr/albums/album01/age.gif

http://www.joinc.co.kr/albums/album01/agf.gif

그러나 ASCII 테이블만 가지고는 일본어, 한글, 중국어와 같은 2byte 문자는 표현할 수 없다. 2byte 문자는 char를 2개 이상 사용해서 저장해야 한다.

이제 마지막으로 문자열이 남았다. C는 문자열을 위한 데이터 타입을 가지고 있지 않다. C에서 문자열을 처리하기 위해서는 배열을 사용해야만 한다. 이것은 원시 데이터 타입을 여러개를 포함하고 있는 데이터 구조다. 예를 들어 문자열은 char를 여러개 포함할 수 있는 데이터 구조를 이용하면 표현할 수 있을 것이다. 배열은 다음장에서 자세히 다루도록 하겠다.

5 typedef 를 이용한 타입 재정의

데이터 타입은 타입에 맞는 고유한 이름을 가지고 사용하게 된다. 그런데 타입의 이름이 너무 길 경우, 이를 이용해서 프로그램을 작성할 경우 불편한 점이 발생한다. 다음의 경우를 보자.
int main() 
{ 
  unsigned long int a; 
  unsigned long int b; 
  unsigned long long c; 
  ... 
} 
 
사용하는데 문제는 없겠지만, 저렇게 긴 타입의 변수가 여기저기에 생성된다면 가독성이 떨어지는 지저분한 코드가 만들어질 가능성이 있다. 이럴경우 typedef 를 이용해서 기존의 데이터 타입을 다른 짧은 이름으로 재정의 해서 사용할 수 있다. typedef는 다음과 같이 사용할 수 있다.
typedef [원래 데이터 형] [재정의될 데이터 타입의 이름] 
 
typedef를 이용하면, 다음과 같이 코드를 깔끔하게 만들 수 있다.
typedef unsigned long int uint; 
typedef unsigned long long ulint; 
 
int main() 
{ 
    uint a; 
    uint b; 
    ulint c; 
} 
 

6 문제

  1. char 데이터 타입을 이용해서 hello world를 화면에 출력해 보자.
    • char를 여러개 써야함.
    • printf 를 통해서 출력할 수 있음.
  2. char 데이터 타입을 이용해서 hello world를 출력해보자. 단 정수형 숫자를 사용해야 한다.
    • ASCII 테이블을 이용하면 됨.
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

유닉스/리눅스 명령어 레퍼런스


파일 명령어

ls - 디렉토리 목록보기
ls -al - 숨은 파일까지 정렬된 형태로 보기
cd dir - dir 디렉토리로 이동
cd - home 디렉토리로 이동
pwd - 현재 위치한 디렉토리 보여주기
mkdir dir - dir라는 디렉토리 만들기
rm file - file을 지우기
rm -r dir - dir 디렉토리를 지우기
rm -f file - 강제로 file 삭제
rm -rf dir - dir 디렉토리와 디렉토리 아래에 있는 모든 파일 삭제
cp file1 file2 - file1을 file2라는 이름으로 복사
cp -r dir1 dir2 - dir1 디렉토리에 있는 것들을 dir2 디렉토리로 복사; dir2가 존재하지 않는다면 만듬
mv file1 file2 - file1을 file2로 이름을 바꾸거나 옮김,
file2가 디렉토리로 존재한다면 file1을 file2 디렉토리로 옮김
ln -s file link - file로 연결된 link라는 심볼릭 링크를만듬
touch file - file을 생성하거나 업데이트
cat > file - 입력을 file로 저장
more file - file의 내용을 출력
head file - file의 첫 10줄을 출력
tail file - file의 마지막 10줄을 출력
tail -f file - file에 추가되는 내용을 출력,마지막10줄부터 출력함


프로세스 관리
ps - 현재 활성화된 프로세스 보여주기
top - 실행중인 모든 프로세스 보여주기
kill pid-프로세스id pid를 종료
killall proc - proc로 시작하는 모든 프로세스 종료
bg - 정지되있거나 화면에서 안보이게 실행중인 프로세스 보여주기; 정지된 프로세스를 화면에 출력하지 않고 계속 진행하기
fg - 화면에 보이지 않게 작동하던 작업 중 최근의 것을 화면에출력하면서 작동시키기
fg n - 화면에 보이지 않게 작동하던 작업 중 n 번째 작업을 화면에 출력하면서 작동시키기


파일 퍼미션
chmod 숫자 file - file의 퍼미션값을 숫자로 바꿈. 숫자는 3자리이며 첫 번째는 소유자,두 번째는 그룹,
세 번째는 익명의권한을 더해서 나타냄.
파일 퍼미션
chmod 숫자 file - file의 퍼미션값을 숫자로 바꿈. 숫자는 3자리이며 첫 번째는 소유자,두 번째는 그룹, 세 번째는 익명의
권한을 더해서 나타냄.

SSH
ssh user@host - user로 host에 접속
ssh -p 포트넘버 user@host - host의 지정한 포트넘버에
user로 접속
ssh-copy-id user@host-사용자명,암호를 입력하지 않고
로그인 할 수 있도록 ssh key를 복사


검색
grep pattern files - file안의 pattern을 찾기
grep -r pattern dir - dir 디렉토리 안에서 재귀적으로pattern 찾기
command | grep pattern - command 명령의 출력에서pattern을 찾는다
locate file - 파일을 찾음


시스템 정보보기
date - 현재 날짜와 시각을 출력
cal - 이번달 달력을 출력
uptime - 현재 기동시간을 출력
w - 온라인인 사용자를 출력
whoami - 어느 사용자로 로그인 하였는지 출력
finger user -user에 관한 정보 출력
uname -a - 커널 정보 출력
cat /proc/cpuinfo - cpu 정보 출력
cat /proc/meminfo - 메모리 정보 출력
man command - command에 대한 매뉴얼 출력
df - 디스크 사용량 출력
du - 디렉토리 사용량 출력
free - 메모리와 스왑 정보 출력
whereis app - app를 실행가능한 위치 출력
which app - app가 기본으로 실행되는 곳을 보여줌


압축
tar cf file.tar files - files들을 포함한 file.tar를 만듬
tar xf file.tar - file.tar을 압축해제
tar czf file.tar.gz files - Gzip 압축을 사용한 압축
tar zxf file.tar.gz - Gzip을 이용해 압축해제
tar cjf file.tar.bz2 - Bzip2 압축을 사용한 압축
tar xjf file.tar.bz2 - Bzip2 압축을 사용한 압축해제
gzip file - file을 압축해서 file.gz로 이름변경
gzip -d file.gz - file.gz를 fiel로 압축해제


네트워크
ping host - host에 핑을 보내 결과 출력
whois domain - domain에 대한 whois 정보 출력
dig domain - domain에 대한 DNS 정보를 출력
dig -x host - 호스트까지의 경로를 되찾아가기


설치
소스로부터 설치
./configure
make
make install
dpkg -i pkg.deb - 패키지 설치(Debian)
rpm -Uvh pkg.rpm - 패키지 설치(RPM)


단축키
Ctrl+C - 현재 명령의 실행을 강제로 마침
Ctrl+Z-현재 명령을 멈춤,fg를 이용해서 계속해서 화면에서 보
이도록 실행하거나 bg 를 이용해서 안보인채 계속 실행
Ctrl+D-현 세션에서 로그 아웃,exit와 비슷
Ctrl+W - 현재 라인에서 한 단어 삭제
Ctrl+U - 현재 줄 전체 삭제
Ctrl+R - 최근 입력한 명령어 보여주기
!! - 마지막 명령어 반복실행
exit - 현재 세션에서 로그 아웃

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

SIGACTION

Section: Linux Programmer's Manual (2)
Updated: 8 May 1999
Index
Return to Main Contents
 

이름

sigaction, sigprocmask, sigpending, sigsuspend - POSIX 시그널 처리 함수  

사용법

#include <signal.h>

int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);

int sigpending(sigset_t *set);

int sigsuspend(const sigset_t *mask);  

설명

sigaction 시스템 호출은 특정 시그널이 수신되었을 때, 프로세스가 취할 액션을 변경하는데 사용된다.

signum 는 시그널을 가리키며, SIGKILLSIGSTOP 를 제외한 모든 시그널 값이 될 수 있다.

act 가 null이 아닐 때, 시그널 signum 에 대한 새로운 액션은 act 가 되며, oldact 이 null이 아닐 때, 기존의 액션은 oldact 에 저장된다.

sigaction 구조는 다음과 같이 정의된다.


struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
}

아키텍쳐에 따라 공용체로 되어 있기도 하므로, sa_handlersa_sigaction 을 모두 지정하지 말라.

sa_restorer 요소는 쓰이지 않으며, 사용되어서는 안된다. POSIX는 sa_restorer 요소를 갖지 않는다.

sa_handlersignum 시그널이 오면 실행되는 액션을 명시하며, 디폴트 액션을 취하라는 SIG_DFL , 시그널을 무시하라는 SIG_IGN , 시그널을 처리하는 특정 함수에 대한 포인터 중의 하나가 될 수 있다. 세번째의 경우 시그널 처리 함수는 시그널 번호만을 유일한 인수로 갖는다.

sa_sigaction 또한 signum 시그널과 연결된 액션을 명시한다. 처리 함수는 시그널 번호를 첫번째 인수로, siginfo_t 에 대한 포인터를 두번째 인수로, 그리고 void형 포인터로 캐스트된 ucontext_t 에 대한 포인터를 세번째 인수로 갖는다.

sa_mask 는 시그널 핸들러의 실행 동안 블록화되어야 하는 시그널의 마스크를 제공한다. 또한, SA_NODEFER 또는 SA_NOMASK 이 사용되지 않으면, 핸들러를 시동시켰던 그 시그널도 블록화된다.

sa_flags 는 시그널 처리 프로세스의 행위를 변경시키는 일련의 플래그들을 명시한다. 이는 bitwise 혹은 플래그는 아래 플래그 들의 0개 이상의 OR 비트 연산으로 만들어진다.


SA_NOCLDSTOP
signumSIGCHLD 이면 자식 프로세스가 중지되어도 통지를 받지 않는다. (즉, 자식 프로세스들이 SIGSTOP, SIGTSTP, SIGTTIN , SIGTTOU 중 하나를 수신할 때)
SA_ONESHOT 또는 SA_RESETHAND
시그널 처리기가 호출되어 한번 실행된 후, 시그널 액션을 원래의 디폴트 액션으로 되돌려 놓는다. (이는 signal(2) 호출에 대한 기본 행위이다.)
SA_RESTART
일부 시스템 호출들이 시그널을 통해 재시작할 수 있도록 함으로서 BSD 시그널과의 호환성을 제공한다.
SA_NOMASK or SA_NODEFER
어떤 시그널 처리기의 동작동안 그 시그널 자신을 막지 않는다.
SA_SIGINFO
시그널 처리기가 한 개가 아닌 3개의 인수를 취한다. 이 경우, sa_handler 대신에 sa_sigaction 이 설정되어야 한다. (sa_sigaction 필드는 리눅스 2.1.86에서 추가되었다.)

sa_sigactionsiginfo_t 변수는 다음의 요소들을 갖는 구조체(struct)이다.


siginfo_t {
int si_signo; /* 시그널 넘버 */
int si_errno; /* errno 값 */
int si_code; /* 시그널 코드 */
pid_t si_pid; /* 프로세스 ID 보내기 */
uid_t si_uid; /* 프로세스를 전송하는 실제 사용자 ID */
int si_status; /* Exit 값 또는 시그널 */
clock_t si_utime; /* 소모된 사용자 시간 */
clock_t si_stime; /* 소모된 시스템 시간 */
sigval_t si_value; /* 시그널 값 */
int si_int; /* POSIX.1b 시그널 */
void * si_ptr; /* POSIX.1b 시그널 */
void * si_addr; /* 실패를 초래한 메모리 위치 */
int si_band; /* 밴드 이벤트 */
int si_fd; /* 파일 기술자 */
}

si_signo, si_errno 그리고 si_code 는 모든 시그널에 대해 정의되었다. kill(2), POSIX.1b 시그널과 SIGCHLD은 si_pidsi_uid 을 채운다. SIGCHLD 은 또한 si_status, si_utime, si_stime 을 채운다. si_int 그리고 si_ptr 는 POSIX.1b 시그널의 송신자에 의해 명시된다. 좀더 자세한 사항을 보려면, sigqueue(2) 을 참조하라. SIGILL, SIGFPE, SIGSEGV 그리고 SIGBUS은 si_addr 를 오류의 주소로 채운다. SIGPOLL 은 si_bandsi_fd 를 채운다. si_code 는 왜 시그널이 보내졌는지에 대해 지시한다. 이는 bitmask가 아닌 값이다. 나올 수 있는 모든 시그널 값은 이 테이블에 나열되어 있다.

si_code
Value Signal origin
SI_USER kill, sigsend or raise
SI_KERNEL The kernel
SI_QUEUE sigqueue
SI_TIMER timer expired
SI_MESGQ mesq state changed
SI_ASYNCIO AIO completed
SI_SIGIO queued SIGIO
SIGILL
ILL_ILLOPC illegal opcode
ILL_ILLOPN illegal operand
ILL_ILLADR illegal addressing mode
ILL_ILLTRP illegal trap
ILL_PRVOPC privileged opcode
ILL_PRVREG privileged register
ILL_COPROC coprocessor error
ILL_BADSTK internal stack error
SIGFPE
FPE_INTDIV integer divide by zero
FPE_INTOVF integer overflow
FPE_FLTDIV floating point divide by zero
FPE_FLTOVF floating point overflow
FPE_FLTUND floating point underflow
FPE_FLTRES floating point inexact result
FPE_FLTINV floating point invalid operation
FPE_FLTSUB subscript out of range
SIGSEGV
SEGV_MAPERR address not mapped to object
SEGV_ACCERR invalid permissions for mapped object
SIGBUS
BUS_ADRALN invalid address alignment
BUS_ADRERR non-existant physical address
BUS_OBJERR object specific hardware error
SIGTRAP
TRAP_BRKPT process breakpoint
TRAP_TRACE process trace trap
SIGCHLD
CLD_EXITED child has exited
CLD_KILLED child was killed
CLD_DUMPED child terminated abnormally
CLD_TRAPPED traced child has trapped
CLD_STOPPED child has stopped
CLD_CONTINUED stopped child has continued
SIGPOLL
POLL_IN data input available
POLL_OUT output buffers available
POLL_MSG input message available
POLL_ERR i/o error
POLL_PRI high priority input available
POLL_HUP device disconnected

sigprocmask 호출은 현재 블록화된 시그널들을 변경시키는데 사용된다. 호출은 지정된 how 값에 따라 다르게 동작한다.


SIG_BLOCK
set 인수가 지정한 시그널 집합이 블록시킬 시그널 집합에 더해진다.
SIG_UNBLOCK
set 에 포함된 시그널들이 블록시킬 시그널들의 집합에서 삭제된다. 블록하고 있지 않은 시그널을 삭제하려 해도 괜찮다.
SIG_SETMASK
블록화할 시그널 집합을 set 으로 설정한다.

oldset 이 null이 아닐 때, 기존의 마스크 시그널 집합은 oldset 에 저장된다.

sigpending 호출은 블록화에 막혀 기다리고 있는 시그널을 살펴볼 수 있도록 해준다. 기다리는 시그널들의 시그널 마스크는 set 내에 저장된다.

sigsuspend 호출은 프로세스가 막고 있는 시그널 마스크를 지정한 mask 로 잠시 대체하고, 다음 시그널이 수신될 때까지 프로세스를 중지시킨다.  

반환값

sigaction , sigprocmask , sigpending 는 성공하면 0을 실패하면 -1을 리턴한다. sigsuspend 항상 -1을 리턴한다. 보통 에러 EINTR 과 함께.

에러

EINVAL
지정한 시그널이 부적절하다. 혹은 받을 수 없는 SIGKILL 또는 SIGSTOP 에 대한 액션을 변경하려고 했다.
EFAULT
act, oldact, set 또는 oldset 이 프로세스의 메모리 영역이 아닌 곳을 가리키고 있다.
EINTR
시스템 호출이 인터럽트되었다.
 

주의

sigprocmask 호출로 SIGKILL 또는 SIGSTOP 을 블록화할 수 없다. 이런 명령은 무시된다.

POSIX에 따르면, 프로세스가 kill() 또는 raise() 함수가 만들어 낸 것이 아닌 GFPE, SIGILL, 혹은 SIGSEGV를 무시한 이후의 프로세스의 동작은 정의되지 않는다. 정수를 0으로 나눈 결과 또한 정의되지 않는다. 일부 아키텍쳐에선 0으로 나누기가 SIGFPE 시그널을 만들어 낼 것이다. (또한 가장 큰 음의 정수를 -1로 나누어도 SIGFPE를 생성할 수 있다.) 이 시그널을 무시하면 무한 루프를 초래할 수 있다.

POSIX 스펙은 오직 SA_NOCLDSTOP 만을 정의한다 . 다른 sa_flags 의 사용은 이식이 불가능하다.

SA_RESETHAND 플래그는 동일한 이름의 SVr4 플래그와 호환가능하다.

SA_NODEFER 플래그는 커널 1.3.9과 새로운 버전하에서 동일한 이름의 SVr4 플래그와 호환가능하다.

SVr4 호환성을 위한 SA_RESETHANDSA_NODEFER 이름들은 오직 라이브러리 버전 3.0.9 그리고 그 이후의 버전에서만 존재한다.

SA_SIGINFO 플래그는 POSIX.1b에 의해서만 명시된다. 이에 대한 지원은 리눅스 2.2에 추가되었다.

sigaction 현재 시그널 처리기에 쿼리를 하기 위해 널 두번째 인수로 호출될 수 있다. 이를 널 두번째 그리고 세번째 인수들로 이를 호출함으로서 현재 머신에 대한 주어진 시그널이 타당한가를 체크하는데 사용될 수 있다.

시그널 체계 조작에 대한 자세한 정보를 얻으려면, sigsetops(3) 을 참조하라.  

호환

POSIX, SVr4. SVr4 는 EINTR 조건에 대한 문서를 제공하지 않는다.  

관련 항목

kill(1), kill(2), killpg(2), pause(2), raise(3), siginterrupt(3), signal(2), signal(7), sigsetops(3), sigvec(2)  

번역

ASPLINUX <man@asp-linux.co.kr> 2000년 7월 29일
한글 Manpage 프로젝트 (http://man.kldp.org) 2005년 2월 13일
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.


Alias 란?

일종의 별명(?)이다. 리눅스 명령어를 사용하다보면 너무 길거나 복잡해서 매번 입력하기 귀찮거나 기억하기 어려운 명령들이 있을 수 있다. 이러한 명령을 자주 사용하지 않는다면 큰 무리가 없겠으나, 개개인의 업무 스타일에 따라 자주 사용하게 된다면 그때마다 매번 명령들을 어렵게 입력해야 하는 고통을 감내해야 한다. alias 기능을 이용하면 어떤 명령이든지, 명령의 길이가 얼마이든지 상관없이, 내가 사용하기 편한 형태로 바꾸어서 사용할 수 있는 것이다.

그럼 간단히 alias를 사용하는 방법에 대해 알아보도록 하자.


Alias 설정

alias는 간단히 alias명령으로 설정이 가능하다. 그러나 이 방법은 시스템을 재부팅하고나면 다시 초기화되므로 매번 적용해야 하는 불편함이 따르게 된다. 그래서 이러한 alias를 특정 파일에 설정해두면 매번 부팅시마다 자동으로 적용되어 쉽게 사용할 수 있게 된다.


alias를 설정하는 파일은 여러 가지가 있을 수 있으나 가장 대표적인 것은 ~/.bashrc 파일이다.
~/.bashrc는 현재 로그인한 해당 계정의 쉘(bash)에 대한 기본 설정을 선언해 두는 곳으로 이곳에 선언된 내용은 해당 계정의 모든 명령에 적용을 받게 된다.
※ 만약 모든 사용자에게 적용하기를 원한다면 /etc/profile 과 같은 곳에 선언해 두면 된다.


일단 ~/.bashrc 파일을 한번 열어보자. 현재 로그인한 계정이 root라면 /root/.bashrc 파일을 열면되고, 일반 사용자 계정이라면 /home/<user-name>/.bashrc 파일을 참조하자.
================
alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'
================


기본적으로 몇 가지 alias가 설정되어 있는 것을 확인할 수 있다. 위의 예에서 'cp -i'는 복사명령(cp) 사용시 동일한 파일명이 있는 경우, 덮어쓰기를 하기전에 덮어쓰기 여부를 물어본다는 뜻이다.
만 약 이러한 alias가 설정되어 있지 않다면, 복사명령 사용시 동일한 파일명이 있어도 묻지 않고 바로 덮어쓰기를 해버리게 되므로 사용자의 실수를 초래할 수 있게 된다. 그럼 위의 방식과 동일하게 실제로 alias를 한번 적용시켜 보자.

우선 지금 시스템에 설정되어 있는 alias의 내역을 확인해보기 위해 alias라는 명령을 넣어보자.
# alias
============================================
alias cp='cp -i'
alias l.='ls -d .* --color=tty'
alias ll='ls -l --color=tty'
alias ls='ls --color=tty'
alias mc='. /usr/share/mc/bin/mc-wrapper.sh'
alias mv='mv -i'
alias rm='rm -i'
alias vi='vim'
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'
============================================
제법 많다. 그럼 이제 alias를 추가해 보자.
 

리눅스에서 파일 및 디렉터리의 리스트를 확인하는 명령으로 ls 명령이 있다. Windows를 사용해본 사용자라면 dir 명령으로 이해하면 될 것이다. Windows와 Linux를 같이 사용하는 사용자라면, 이 ls 명령을 Windows의 명령과 혼동하는 경우가 가끔 있었을 것이다. 그래서 Linux에서도 dir이라는 명령으로 사용할 수 있도록 설정해보자.

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

alias dir='ls -al'

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


위와 같이 입력하자. 위 내용은 사용자가 dir이라는 명령을 입력했을때, ls -al 명령을 입력한 것과 동일하게 동작하라는 뜻이다. 필자가 ls명령에 -al 옵션을 추가한 이유는 리눅스의 ls 명령은 일반 파일과 디렉터리만을 보여줄 뿐 숨김속성이 있는 파일들이나 디렉터리는 보여주지 못하며, 파일 및 디렉터리의 상세 내용도 볼 수가 없으므로, -al 옵션을 통해서숨김속성이 있는 것들도 보여주고 각 리스트의 상세 내역도 같이 출력하라는 의미에서 옵션을 추가해준 것이다.
 

이렇게 설정하였다고 해서 바로 그 명령이 적용되는 것은 아니다. ~/.bashrc 파일은 로그인 시에 해당 내용을 읽어서 적용하므로 다음번 로그인 이후에나 위의 내용은 적용된다. 만약 바로 적용되는 모습을 보고자 한다면, ~/.bashrc 파일에 기록하지 말고, 터미널 상에 바로 명령을 입력해 보자.

# alias dir='ls -al'


※ 또는 위에 설정한 ~/.bashrc의 내용을 바로 적용하기 위해 아래와 같은 명령을 사용해 주어도 된다.
# source ~/.bashrc
이제 dir 명령과 ls -al 명령을 번갈아 넣어 보자. 동일한 결과가 출력되는가?

alias를 설정하는 또 다른 방법으로는...
앞서 말했던 /etc/profile에 설정하여 모든 사용자에게 적용하는 방법 이외에도 /etc/rc.local에 선언하는 방법도 있다.
/etc/rc.local은 리눅스가 부팅되면서 자동으로 실행할 명령들을 선언해 두는 곳으로 여기에 선언된 내용 역시 동일하게 적용받을 수 있게 된다.



Alias 사용 예

앞서 살펴본 바와 같이 alias 명령은 다양한 방식으로 사용이 가능하다. 아래에 대표적인 사용예를 몇가지 찾아보았다.


① 파일 삭제시 삭제여부를 다시 묻지 않고, 디렉터리 하위에 파일 및 디렉터리가 존재하더라도 강제로 삭제한다.
  # alias rm='rm -rf'

 ※ 삭제 여부를 묻지 않으므로, 이제부터 rm 명령 사용시에 주의를 기울여야 한다.
 

② CD-ROM을 쉽게 마운트 하자.
  # alias cdrom='mount /dev/cdrom /media/cdrom'

 ※ 시스템에 따라 CD-ROM 디바이스의 명칭 또는 마운트 디렉터리가 상이할 수 있다.

     자신의 시스템에 맞는 것을 사용하자.
 

③ (지정된) Windows의 공유 디렉터리를 쉽게 마운트하자.
  # alias win_smb='mount -t smbfs //192.168.0.1/data /media/samba'

 ※ 네트워크 환경에 따라 ip 주소 및 마운트하는 경로가 다르므로 적절히 수정해서 사용하자.
 

④ 매번 반복되는 데이터 백업(tar)을 쉽게 하자.
  # alias backup='tar czvf web_backup.tar.gz /var/www/html'

 ※ 위와 같이 backup 이라는 alias 명령을 만든 다음, 이 명령을 cron을 통해 자동화(스케줄링) 하면 된다.
 

⑤ 웹서버(httpd) 데몬을 쉽게 구동하자.
  # alias web='/etc/init.d/httpd'
  # web {start|stop|restart}

 ※ 이제는 web 이라는 명령으로 웹서버 구동이 가능해진다. (# web start)


'Programming > Linux' 카테고리의 다른 글

유닉스/리눅스 명령어 레퍼런스  (0) 2008.03.26
Man Page/sigaction  (0) 2008.03.26
POSIX?  (0) 2008.03.24
Ext2 파일시스템의 구조(2)  (0) 2008.03.20
Ext2 파일시스템의 구조  (0) 2008.03.20
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

POSIX

위키백과 ― 우리 모두의 백과사전.

이식 가능 운영 체제 인터페이스(移植可能運營體制 interface; 영어: portable operating system interface), 약칭 POSIX(‘파식스’ 또는 ‘포식스’)는 서로 다른 UNIX OS의 공통 API를 정리하여 이식성이 높은 유닉스 응용 프로그램을 개발하기 위한 목적으로 IEEE가 책정한 애플리케이션 인터페이스 규격이다.

POSIX의 마지막 글자 X는 유닉스 호환 운영체제에 보통 X가 붙는 것에서 유래한다.

규격의 내용은 커널로의 C 언어 인터페이스인 시스템 콜 뿐 아니라, 프로세스 환경, 파일과 디렉터리, 시스템 데이터베이스(암호 파일 등), tar 압축 포맷 등 다양한 분야를 아우른다.

유닉스 계열 외에 마이크로소프트 윈도 NT는 POSIX 1.0에 준하는 POSIX 서브 시스템을 탑재하고 있으며, POSIX 응용 프로그램을 서브 시스템에서 실행할 수 있다. 이는 주로 미국 정부기관의 컴퓨터 시스템 토입조건(FIPS)에서 POSIX 준거할 것을 요구하기 때문이다. 윈도 2000까지 POSIX 서브시스템을 탑재하고 있었지만 윈도 XP에서 폐지되었다.

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

An inode contains the following information about a file:
- The type of file and the access modes
- The UID and GID numbers of the file’s owner and group
- The size of the file
- The time the file was last accessed or modified, and the inode changed
- The total number of data blocks used by, or allocated to the file The inode contains two types of pointers:

direct pointers and indirect pointers.


사용자 삽입 이미지



Direct Pointers

There are 12 direct pointers, which refer directly to data blocks.

The 12 direct pointers can directly reference the data blocks for a file up to 96 Kbytes.


Indirect Pointers


The three types of indirect pointers are:


Single indirect pointer – A single indirect pointers refers to a file system block containing pointers to data blocks. This file system block contains 2048 additional addresses of 8-Kbyte data blocks, which can point to an additional 16 Mytes of data.


Double indirect pointer – A double indirect pointer refers to a file system
block containing single indirect pointers. Each indirect pointer refers to a
file system block containing the data block pointers. Double indirect
pointers points to an additional 32 Gbytes of data.


Triple indirect pointer – A triple indirect pointer can reference up to an dditional 70 Tbytes of data. However,

the maximum file size is limited to 1 Tbyte in a ufs file system.

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.
사용자 삽입 이미지

○ 슈퍼 블록(Super block)
    - 파일시스템에 대한 제어 정보
         * 파일시스템의 종류(magic number)
         * 블록의 크기
         * 파일시스템이 가지고 있는 inode의 갯수
         * 파일시스템이 가지고 있는 블록의 갯수
         * 비어있는 indoe의 갯수와 블록의 갯수
         * 블록 그룹의 크기
         * 각 블록 그룹에 포함된 inode의 갯수
      ※ 실질적으로 슈퍼블록은 파일시스템에 하나만 존재하면 되지만 만일 하나의 수퍼블록만 저장
          될 경우 슈퍼블록의 저장된 섹터가 불량이되면 파일시스템 전체를 접근할 수 없게됨

○ 그룹 디스크립터(Group descriptors)
   - 블록 그룹에 대한 제어 정보
         * inode 비트맵의 위치
         * 블록 비트맵의 위치
         * inode table의 위치
         * 그룹 내에 비어있는 inode의 갯수
         * 그룹내에 비어있는 블록의 갯수

○ 블록 비트맵(Block bitmap)
   - 한 블록 그룹에 포함된 모든 블록의 할당 상태를 나타냄
   - 한 비트가 한 블록의 상태를 표시

○ inode 비트맵(inode bitmap)
   - 한 블록 그룹에 포함된 모든 inode의 할당 상태를 나타냄
   - 한 비트가 한 inode의 상태를 표시

○ Ext2가 파일시스템을 블록 그룹으로 분할하는 이유
   - 파일 및 메타데이터 접근의 지역성(locality)을 이용하여 디스크 접근 시간을 줄임
         * 파일의 데이터와 inode를 가까운 위치에 배치
         * 같은 디렉토리에 속한 파일을 가까운 위치에 배치

+ Recent posts