오늘은 SUSv3에서 정의한 기능 테스트 매크로와 표준 시스템 데이터형을 소개하겠다.
- 기능 테스트 매크로
시스템 호출과 라이브러리 함수 API의 동작에 대한 여러 가지 표준이 존재한다. 오픈 그룹 같은 포준 단체가 정의한 표준도 있고, 역사적으로 중요한 두가지 유닉스 구현인 BSD와 시스템 V 릴리스 4가 정의한 표준도 있다.
이식성 있는 응용 프로그램을 작설할 때는 헤더 파일이 특정 표준을 따르는지를 나타내는 정의가 있으면 편리할 때가 있다. 이를 위해 프로그램을 컴파일 할 때 아래 나열된 기능 테스트 매크로를 정의한다. 매크로를 정의하는 방법 중 하나는 프로그램 소스에서 헤더 파일을 선언하기 전에 매크로를 정의하는 것이다.
#define _BSD_SOURCE 1
또 다른 방법으로, 컴파일러의 -D 옵션을 쓸 수도 있다.
$ cc -D_BSD_SOURCE prog.c
다음과 같은 기능 테스트 매크로가 관련 표준에 정의되어 있으며, 따라서 이 매크로는 해당 표준을 지원하는 모든 시스템에서 이식성이 있다.
- _POSIX_SOURCE : 특정 값으로 정의되어 있으면, POSIX.1-1990과 ISO C 호환기능을 제공한다. 이 매크로는 _POSIX_C_SOURCE로 대체됐다.
- _POSIX_C_SOURCE : 1로 정의되어 있으면 _POSIX_SOURCE와 동일한 효과를 낸다. 199309 이상의 값으로 정의되어 있으면 POSIX.1b 기능도 제공한다. 199506 이상의 값으로 정의되어 있으면 POSIX.1c (스레드) 기능도 제공한다. 200112로 정의되어 있으면 POSIX.1-2001 기본 표준 기능도 제공한다. 200809로 정의되어있으면 POSIX.1-2008 기본 표준 기능도 제공한다.
- _XOPEN_SOURCE : 특정 값으로 정의되어 있으면 POSIX.1, POSIX.2, X/Open 기능을 제공한다. 500 이상의 값으로 정의되어 있으면 SUSv2 확장 기능도제공한다. 600 이상의 값으로 설정하면 추가적으로 SUSv3 XSI 확장기능과 C99 확장기능을 제공한다. 700 이상으로 설정하면 SUSv4 XSI 확장기능도 제공한다.
다음은 glibc 고유의 기능 테스트 매크로다.
- _BSD_SOURCE : 어떤 값이든 정의되어 있으면, BSD의 기능을 제공한다. 이 매크로를 정의하면 _POSIX_CSOURCE도 199506으로 정의된다. 명시적으로 이 매크로만 설정하면 표준이 상충되는 몇몇 경우에 BSD 표준을 따르게 된다.
- _SVID_SOURCE : 어떤 값이든 정의되어 있으면, 시스템 V 인터페이스 정의의 기능을 제공한다.
- _GNU_SOURCE : 어떤 값이든 정의되어 있으면, 이상의 모든 매크로를 설정해서 모든 기능을 제공할 뿐 아니라 다양한 GNU 확장 기능도 제공한다.
GNU C 컴파일러가 특별한 옵션 없이 실행되면 _POSIX_SOURCE, _POSIX_C_SOURCE=200809, _BSD_SOURCE, _SVID_SOURCE가 기본적으로 정의된다.
개별 매크로를 정의하거나 컴파일러를 표준 모드중 하나로 실행하면, 해당 기능만 제공된다. 예외가 하나 있는데, _POSIX_C_SOURCE가 정의되지 않고 컴파일러가 표준 모드중 하나로 실행되지 않으면, _POSIX_C_SOURCE가 200809로 정의된다.
여러 매크로를 동시에 정의하면 해당 기능이 모두 제공되므로, 예를 들어 다름과 같은 cc 명령을 이용해서 기본 설정과 동일한 매크로 설정을 명시적으로 선택할 수도 있다.
$ cc -D_POSIC_SOURCE -D_POSIX_C_SOURCE=199506 \
-D_BSD_SOURCE -D_SVID_SOURCE prog.c
<features.h> 헤더파일과 feature_test)macros(7) 메뉴얼 페이지를 보면 각기능 테스트 매크로에 정확히 어떤 값이 할당되어 있는지를 알 수 있다.
_POSIX_C_SOURCE, _XOPEN_SOURCE, POSIX.1/SUS
POSIX.1-2001/SUSv3에는 _POSIX_C_SOURCE와 _XOPEN_SOURCE 기능 테스트 매크로만 규정되어 있으며, 호환 응용 프로그램의 경우 이 값들을 각각 200112와 600으로 정의하도록 요구한다. _POSIX_C_SOURCE를 200112로 정의하면 POSIX.1-2001 기본 규격호환성을 제공한다. _XOPEN_SOURCE를 600으로 정의하면 SUSv3 호환성을 제공한다. POSIX.1 - 2008/SUSv4의 경우도 이와 유사하게, _POSIX_C_SOURCE와 _XOPEN_SOURCE를 각각 200809와 700으로 정의해야 한다.
SUSv3에 따르면, _XOPEN_SOURCE를 600으로 설정하면 _POSIX_C_SOURCE를 200112로 설정했을때 제공되는 모든 기능을 제공해야 한다. 따라서 SUSv3호환성을 위해 응용 프로그램은 _XOPEN_SOURCE만 정의하면 된다. SUSv4도 이와 유사하게 _XOPEN_SOURCE를 700으로 설정하면 _POSIX_C_SOURCE를 200809로 설정했을때 제공되는 모든 기능을 제공해야 한다.
함수 프로토타입과 소스코드 예제의 기능 테스트 매크로
매뉴얼 페이지를 보면 헤더 파일의 특정 상수 정의나 함수 선언을 쓰려면 어떤 기능 테스트 매크로를 정의해야 하는지를 알 수 있다.
- 시스템 데이터형
프로세스 ID, 사용자ID, 파일 오프셋 등 여러가지 구현 데이터형이 표준 C 데이터형으로 표현되어 있다. 이런 정보를 저장하는 변수를 선언하기 위해 int나 long 같은 C의 기초 데이터형을 쓸 수도 있겠지만, 그렇게 하면 다음과 같은 이유로 유닉스 시스템 간의 이식성이 떨어진다.
- 이 기초 데이터형의 크가기 유닉스 구현마다 다르거나, 심지어 같은 구현이라도 컴파일환경에 따라 다를 수 있다. 그 뿐 아니라 같은 정보를 나타내더라도 구현에 따라 다른 데이터형을 쓰기도 한다. 예를 들어, 프로세스 ID가 한 시스템에서는 int이지만 다른 시스템에서는 long일 수도 있다.
- 같은 종류의 유닉스 구현에서도 버전에 따라 정보를 나타내는 데 쓰는 데이터형이 다를 수 있다. 리눅스상의 유명한 예는 사용자 ID와 그룹ID다. 리눅스 2.2까지는 이 값을 16비트로 나타냈는데, 리눅스 2.4부터는 32비트 값으로 바뀌었다.
이런 이식성 문제를 피하기 위해, SUSv3는 여러가지 표준 시스템 데이터형을 명시했고, 구현이 이 데이터형을 적절히 정의하고 사용하도록 요구했다. 이 데이터형은 C의 typedef 기능으로 정의됐따. 예를 들어 pid_t 데이터형은 프로세스 ID를 나타내는데, 리눅스 /x86-32에서는 다음과 같이 정의되어 있다.
typedef int pid_t;
표준 시스템 데이터형의 이름은 대부분 _t로 끝난다. 다른 헤더 파일에 정의되어 있는 것도 있지만, 상당수는 <sys/types.h> 에 정의되어 있다.
이식성을 위해 응용 프로그램은 이 데이터형 정의를 사용해야 한다. 예를 들어, 다음과 같이 선언하면 응용 프로그램은 모든 SUSv3 호환 시스템에서 올바르게 프로세스 ID를 나타낼 수 있다.
pid_t mypid;
아래 표는 시스템 데이터형 중 대표적인 몇가지의 예시이다.
데이터형 | SUSv3 데이터형 요구사항 | 실행 |
blkcnt_t | 부호 있는 정수 | 파일 블록 수 |
blksize_t | 부호 있는 정수 | 파일 블록 크기 |
cc_t | 부호 없는 정수 | 터미널 특수문자 |
clock_t | 정수 또는 부동소수점 실수 | clock tick 으로 나타낸 시스템시간 |
clockid_t | 산술형 | POSIX.1b 클록과 타이머 함수용 클록ID |
comp_t | SUSv3에 없음 | 압축된 클록 틱 |
dev_t | 산술형 | 주번호와 부번호로 이루어진 디바이스번호 |
DIR | 데이터형 요구사항 없음 | 디렉토리 스트림 |
fd_set | 구조체형 | select()용 파일 디스크립터 |
fsblkcnt_t | 부호 없는 정수 | 파일 시스템 블록 수 |
fsfilcnt_t | 부호 없는 정수 | 파일 수 |
uid_t | 정수 | 숫자로 나타낸 사용자 ID |
gid_t | 정수 | 숫자로 나타낸 그룹 ID |
id_t | 정수 | ID를 담는 일반적인 데이터형, 최소한 pid_t, uid_t, gid_t를 담을 만큼 커야한다. |
in_addr_t | 32비트 부호 없는 정수 | IPV4 주소 |
in_port_t | 16비트 부호 없는 정수 | IP 포트번호 |
ino_t | 부호 없는 정수 | 파일 i-노드번호 |
key_t | 산술형 | 시스템 V IPC키 |
mode_t | 정수 | 파일 권한과 종류 |
mqd_t | 데이터형 요구사항 없지만, 배열형은 안됨 | POSIX 메시지 큐 디스크립터 |
msglen_t | 부호 없는 정수 | 시스템 V 메시지 큐에 허용되는 바이트 수 |
msgqnum_t | 부호 없는 정수 | 시스템 V 메시지 큐에 들어있는 메시지 수 |
nfds_t | 부호 없는 정수 | poll()용 파일 디스크립터 수 |
nlink_t | 정수 | 파일을 가리키는 하드링크의 수 |
off_t | 부호 있는 정수 | 파일 오프셋 또는 크기 |
pid_t | 부호 있는 정수 | 프로세스 ID, 프로세스 그룹 ID, 세션 ID |
ptrdiff_t | 부호 있는 정수 | 부호 있는 정수로 나타낸, 두 포인터 값의 차이 |
rlim_t | 부호 없는 정수 | 자원 한도 |
sa_family_t | 부호 없는 정수 | 소켓 주소 체계 |
shmatt_t | 부호 없는 정수 | 시스템 V 공유 메모리 세그먼트에 부착된 프로세스의 수 |
sig_atomic_t | 정수 | 아토믹하게 접근할 수 있는 데이터형 |
siginfo_t | 구조체형 | 시그널의 출처에 대한 정보 |
sigset_t | 정수 또는 구조체형 | 시그널 |
size_t | 부호 없는 정수 | 바이트 수로 나타낸 객체의 크기 |
socklen_t | 최소 32비트 정수형 | 바이트 수로 나타낸 소켓 주소 구조체의 크기 |
speed_t | 부호 없는 정수 | 터미널 라인 속도 |
ssize_t | 부호 있는 정수 | 대체 시그널 스택 설명 |
suseconds_t | -1 ~ 1000000 범위내의 부호있는 정수 | 마이크로 초 시간 간격 |
lcflag_t | 부호 없는 정수 | 터미널 모드 플래그 비트 마스크 |
time_t | 정수 또는 부동소수점 실수 | 기원 이후 흐른 초로 나타낸 달력시간 |
timer_t | 산술형 | POSIX.1b 타이머 함수용 타이머 |
'리눅스 > 시스템 개념' 카테고리의 다른 글
5. 명령행 옵션과 인자 (0) | 2019.09.27 |
---|---|
4. 시스템 호출과 라이브러리 함수 에러처리 (0) | 2019.09.26 |
3. 표준 C 라이브러리 : GNU C 라이브러리(glib) (0) | 2019.09.26 |
2. 라이브러리 함수 (0) | 2019.09.26 |
1.시스템 호출 (0) | 2019.09.26 |