내 답이 정답인지는 모르지만 . . .
한빛아카데미의 <시스템 프로그래밍 유닉스 & 리눅스> 의 연습문제 풀이입니다 😁
다음 중 리눅스/유닉스 시스템 프로그래밍과 관련 있는 표준이 아닌 것은?
1. ANSI C 표준
2. POSIX
3. 다중 유닉스 명세
4. 시스템 V 인터페이스 정의
답은 3. 다중 유닉스 명제
POSIX는 유닉스에 기반을 두고 있는 표준 운영체제 인터페이스로 서로 다른 유닉스 시스템 사이에서 상호 이식이 가능한 응용 프로그램을 개발하기 위해 정해진 표준이기에 관련 있음! 땅땅
시스템 V 인터페이스 정의는 AT&T 유닉스 시스템 V의 인터페이스를 정의하는 SVID(system V interface definition)은 프로그램과 장치에서 이용할 수 있는 시스템 호출과 C 라이브러리에 관한 표준을 포함하기에 관련 있음!
3번에 나오는 다중 유닉스 명제가 아니라 단일 유닉스 명제가 관련 있음!
덧붙이자면, 단일 유닉스 명제 (SUS)는 운영체제가 유닉스라는 이름을 사용하기 위해 지켜야 하는 표준의 총칭이다.
man 페이지 번호에서 시스템 호출을 나타내는 섹션 번호는?
1. 1
2. 2
3. 3
4. 5
답은 2. 2
메뉴얼은 항목의 종류에 따라 섹션이 구분되어 있는데,
추가로, man 명령으로 검색하면 섹션 번호가 가장 낮은 것이 기본으로 출력된다!
ex. read에 대해 명령도 시스템 호출도 있다면 섹션 1의 내용이 먼저 출력된다는 뜻!
시스템 호출이 실패하면 -1을 리턴한 뒤 오류 코드를 특정 변수에 저장한다. 이 변수명은?
1. eno
2. error
3. enum
4. errno
답은 4. errno
시스템 호출이 성공적으로 수행되면 0을 리턴하고 실패하면 -1을 리턴함과 동시에 전역 변수인 errno에 오류코드를 저장한다.
vi /usr/include/asm-generic/errno-base.h
리눅스 기본 명령 중 패턴을 검색할 때 사용하는 명령은?
1. ls
2. cat
3. grep
4. which
답은 3. grep
각각 명령의 기능을 나열해보자면,
han.c를 컴파일할 때 실행 파일명을 han으로 하려고 한다. gcc의 옵션을 바르게 설정한 것은?
1. gcc han.c
2. gcc -c han han.c
3. gcc -a han han.c
4. gcc -o han han.c
답은 4번. gcc -o han han.c
gcc의 기본 형식은 gcc [옵션][파일명]이며,
-c 옵션을 사용하면 오브젝트 파일만 생성한다는 뜻이고
-o [실행파일명] <- 이렇게 사용하면 지정한 이름으로 실행 파일을 생성한다는 뜻이다.
시스템 호출과 라이브러리 함수의 차이점을 동작 과정 비교를 통해 설명하시오.
시스템 호출이란 프로그램을 구현할 수 있도록 제공되는 프로그래밍 인터페이스를 말하고, 라이브러리는 미리 컴파일된 함수를 묶어서 제공하는 특수한 형태의 파일이다.
둘 다 응용 프로그램을 작성할 때 사용되지만,
시스템 호출이 커널의 해당 모듈을 직접 호출해 작업하고 결과를 리턴하는 반면
라이브러리 함수는 커널 모듈을 직접 호출하지 않고 함수 내부에서 시스템 호출을 사용한다는 차이가 있다.
간단히 이야기하면 커널의 모듈을 직접 호출 하느냐 하지 않느냐 !
호출하는 것이 시스템 호출, 직접 호출하지 않고 내부에서 시스템 호출을 사용하는 것이 라이브러리 함수
man write 명령을 실행했는데, write()함수가 아니라 write 명령에 대한 매뉴얼이 출력되었다. write() 함수의 매뉴얼을 보려면 어떻게 해야할까?
매뉴얼은 항목의 종류에 따라 섹션이 구분되어 있다. 리눅스에서 사용하는 일반적인 명령에 대한 설명은 섹션 1, 시스템 호출은 섹션 2, 라이브러리 함수는 섹션 3에 속한다.
여기서 중요한 점은, man 명령으로 검색하면 ⭐️ 섹션 번호가 가장 낮은 것이 기본으로 출력된다는 것이다.
따라서 man write를 실행했을 때, 섹션 번호가 낮은 명령(1)이 라이브러리 함수(3)인 write()보다 먼저 나오게 된 것이다.
섹션 3의 write() 에 대한 설명을 보려면 다음과 같이 해당 섹션을 지정해야 한다
man -s 3 write
시스템 호출에서 오류가 발생하면 errno 변수에 오류의 원인을 설명하는 숫자가 저장된다. 오류 번호가 1이라면 어떤 오류일까?
errno에 저장된 값 1이 의미하는 바를 해석하려면 헤더 파일을 참조해야 한다.
리눅스는 asm-generic/errno-base.h 파일에, 유닉스는 sys/errno.h 파일에 정의되어 있다.
errno = 1이 의미하는 것은 EPERM 으로 정의되어 있으며 이것은 Operation not permitted 즉, 대개 허용되지 않은 권한으로 접근하였을 때 발생하는 오류이다.
[예제 1-1]을 수정해 errno 번호 뿐만 아니라 오류 메시지도 출력되도록 코드를 수정하시오. [예제 1-4 참조]
perror() 는 errno에 저장된 값을 읽어 이에 해당하는 메세지를 표준오류로 출력한다.
perror() 함수의 인자로 지정한 문자열과 콜론(:)을 출력한 후 오류 메세지를 출력하는데,
인자가 NULL이면 콜론은 출력하지 않고 오류 메세지만 출력한다.
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
int main(){
if(access("test.txt", R_OK) == -1){
perror("test.txt");
exit(1);
}
}
결과
test.txt: No such file or directory
gcc로 소스 코드를 컴파일했더니 실행 파일 a.out이 만들어졌다. 실행 파일을 ex10.exe로 만들려면 어떻게 해야할까?
gcc를 이용하여 컴파일할 때, 파일명을 별도로 지정하지 않으면 a.out이라는 이름으로 실행 파일이 생성된다.
따라서 실행 파일을 ex10.exe로 만들고 싶다면 -o 옵션을 사용하여 실행 파일 이름을 지정해주어야한다.
예시 ) gcc -o ex10.exe (컴파일하려는 c파일).c
gcc로 소스 코드를 컴파일 해 실행 파일은 ex11.exe를 만들었다. ls 명령으로 확인하면 ex11.exe가 보이는데, ex11.exe를 실행하면 파일을 찾을 수 없다고 한다. 무엇이 문제이고 어떻게 해결할 수 있는지 설명하시오.
(어느 질문보다 확실하지 않음 주의🥲)
1 - 실행 권한이 없는 경우
파일을 실행 가능하게 변경해야한다.
chmod +x ex11.exe
2 - 실행 경로 문제
ex11.exe 파일을 현재 작업 디렉토리에서 실행하지 못하는 경우 파일을 찾지 못할 수 있다. 이 경우에는 파일이 어디에 위치하는지 정확한 경로를 지정해야 한다.
예를 들어,
./ex11.exe // 현재 디렉토리에서 ex11.exe 실행
[예제 1-3]에서 인자로 받은 두 정수의 뺄셈을 계산해 리턴하는 subnum() 함수를 subnum.c 파일로 만들고 Makefile을 수정해 실행 파일을 생성한 뒤 실행 결과를 확인하시오.
예제와 거의 동일하고 덧셈 부분을 뺄셈으로만 바꾸면 되니 생략~
프로그램을 실행하는 도중에 정숫값 200개를 저장할 수 있도록 메모리를 할당하려면 어떻게 해야할까?
프로그램을 실행하는 도중에 필요한 메모리 공간을 할당하고 더 이상 사용하지 않으면 해당 공간을 해제하는 것이 바로 동적 메모리 할당이다.
메모리 할당 함수로는 malloc(), calloc() realloc()이 있다.
#include <stdio.h>
#include <stdlib.h>
int main() {
int *myArray; // 포인터를 선언
myArray = malloc(200 * sizeof(int)); // 200개의 정수를 저장할 메모리를 할당
free(myArray); // 메모리를 해제
return 0;
}
myArray = (int *)calloc(200, sizeof(int)); // 200개의 정수를 저장할 메모리를 할당하고 0으로 초기화
calloc 함수는 malloc 과 유사하지만 메모리를 초기화하여 모든 요소를 0으로 설정 한다는 점에서 차이가 있다.
또한, 메모리 할당 후에는 메모리를 사용한 후 'free' 함수를 사용해 메모리를 해제해야 메모리 누수를 방지할 수 있다.
명령행 인자로 정숫값(작은 수, 큰 수) 2개를 받아서 앞의 값부터 뒤의 값까지 합계를 구하는 프로그램을 작성하시오.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
if (argc != 3) {
printf("사용법: %s [첫 번째 정수] [두 번째 정수]\n", argv[0]);
return 1;
}
int num1 = atoi(argv[1]); // 첫 번째 정수로 변환
int num2 = atoi(argv[2]); // 두 번째 정수로 변환
int sum = 0;
for (int i = num1; i <= num2; i++) {
sum += i;
}
printf("%d부터 %d까지의 합계: %d\n", num1, num2, sum);
return 0;
}
프로그램 실행 시 두 개의 정수를 명령행에 전달해야 한다.
./(프로그램명) 2 7
명령행 인자와 getopt()함수를 사용해 다음 명령을 처리하는 프로그램을 작성하시오.
1) 명령의 이름: ex1_15.out
2) 명령의 옵션과 동작
- 인자가 없을 경우: -h 처럼 사용 가능한 옵션의 목록 출력
- -p: "Welcome Linux System Programming!" 출력
- -n 인자: "Nice to meet 인자" 형태로 출력
- -h : 사용 가능한 옵션의 목록 출력
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
int opt;
int name_option = 0;
char *name = NULL;
while ((opt = getopt(argc, argv, "hpn:")) != -1) {
switch (opt) {
case 'h':
printf("Usage: %s [OPTIONS]\n", argv[0]);
printf("Options:\n");
printf(" -h Print this help message\n");
printf(" -p Print 'Welcome Linux System Programming!'\n");
printf(" -n NAME Print 'Nice to meet NAME'\n");
exit(0);
case 'p':
printf("Welcome Linux System Programming!\n");
name_option = 1;
break;
case 'n':
name = optarg;
name_option = 1;
break;
default:
fprintf(stderr, "Usage: %s [-h] [-p] [-n NAME]\n", argv[0]);
exit(1);
}
}
if (!name_option) {
printf("No option provided. Use -h for help.\n");
} else if (name != NULL) {
printf("Nice to meet %s!\n", name);
}
return 0;
}
그리고 이 프로그램은 명령행에서 아래와 같이 실행된다!
./ex1_15.out -p
./ex1_15.out -n John
./ex1_15.out -h
./ex1_15.out
실행 결과
Welcome Linux System Programming!
Nice to meet John!
Usage: ./ex1_15.out [OPTIONS]
Options:
-h Print this help message
-p Print 'Welcome Linux System Programming!'
-n NAME Print 'Nice to meet NAME'
시작이 반이다 ! 1장 끝! 👊🏻