C언어 학습의 필요성
- 리눅스 커널은 C로 작성되어 있습니다. 따라서 커널의 구조와 동작 방식을 이해하려면 C 언어에 대한 지식이 필요합니다.
- 추상화 언어의 최적화 가능
- I/O 성능과 버퍼링 이해 가능: C를 통해 버퍼, 블로킹/논블로킹 I/O, 파일 디스크립터, select/poll 등 성능과 밀접한 개념 이해
- 메모리, 포인터, 시스템 콜, 버퍼링, 프로세스/스레드 같은 개념을 C로 직접 경험하면,
- JVM·GC 내부 동작
- 네트워크 I/O 병목
- 대용량 데이터 처리 최적화
- 성능 튜닝
이런 영역에서 문제를 더 깊이 이해하고 해결할 수 있는 기반이 생깁니다.
포인터란?
포인터(pointer)는 메모리 주소를 저장하는 변수입니다.
포인터기호
- & : 주소 연산자, ~의 주소를 구해라.
- * : 역참조 연산자, 그 주소에 있는 값을 가져와라.
- int * p : "p는 int를 가리키는 주소(포인터)이다" 라는 선언
- 주소는 "포인터 타입"이라고하는 별도의 타입을 보유하고 있다. 주소는 숫자처럼 생겼지만, 숫자처럼 쓰면 안 되는 특별한 "종류의 값임
- 역참조 연산자는 변수의 값을 바꿀때 주로 사용됨
int x = 10;
int *p = &x; // 선언 → p는 int를 가리키는 포인터
printf("%p\n", p); // p: 주소 자체
printf("%d\n", *p); // *p: 주소에 있는 값 (즉, x)
C에서는 함수 인자 전달 방식이 "값 복사(pass by value)"
int a = 10;
change(a);
printf("%d\n", a); // 👉 여전히 10! 안 바뀜
int a = 10;
change(&a); // a의 주소를 전달
printf("%d\n", a); // 👉 100! 값이 실제로 바뀜
Java에서도 함수 인자 전달 방식이 "값 복사(pass by value)"
public static void main(String[] args) {
int a = 10;
change(a);
System.out.println(a); // ➤ 10 (안 바뀜)
}
public static void main(String[] args) {
Box box = new Box();
box.value = 10;
change(box);
System.out.println(box.value); // ➤ 100 (바뀜!)
}
자료타입
int fd[2]; : 정수형 2개를 담을 수 있는 배열 변수 fd를 선언한다.
포인터를 활용한 변수변환 함수
pipe(int fd[2]);는 어떻게 출력(return)의 의미가 되는가?
C 언어는 하나의 값만 return할 수 있기 때문에, 여러 값을 반환할 필요가 있을 때는 "포인터(주소)"를 인자로 받아서 그 안에 값을 담아주는 방식을 씁니다.
구조체(struct)란
서로 다른 타입의 데이터들을 하나로 묶어서 "하나의 새로운 데이터 타입"으로 정의하는 것.
- Person 이라는 새로운 데이터 타입을 만들었고, name, age, height 라는 서로 다른 타입을 묶어 하나로 보관.
- 보통 메서드 없 속성만 가짐
struct epoll_event {
uint32_t events; /* EPOLLIN, EPOLLOUT 같은 이벤트 플래그 */
epoll_data_t data; /* 유저가 지정할 데이터, 보통 fd */
};
Union이란
여러 멤버(필드)를 같은 메모리 공간에 겹쳐서 저장하는 C/C++ 의 데이터 타입
- struct 는 멤버들이 메모리를 각각 따로 차지하지만,
- union 은 모든 멤버가 같은 메모리 위치를 공유.
union Example {
int x;
float y;
};
typedef union 은? : typedef 를 붙여서 별명(타입 이름)을 만들어주는 것.
typedef union epoll_data {
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
} epoll_data_t;
Example_t 로 타입을 선언할 수 있으며 데이터 구조 내에 아 중 하나로 쓸 수 있게 함.
- pointer
- file descriptor
- 32bit 정수
- 64bit 정수
✅ 백엔드 개발자가 알아야 할 주요 시스템콜 목록
📁 1. 파일 및 입출력 관련
시스템콜설명
open() | 파일 열기 → FD 반환 |
read() | FD로부터 바이트 단위 데이터 읽기 |
write() | FD에 바이트 단위 데이터 쓰기 |
close() | 열린 파일 디스크립터 닫기 |
lseek() | 파일 커서 위치 이동 |
fsync() | 버퍼링된 데이터를 디스크에 강제 저장 |
fstat() | 파일 정보 조회 (크기, 권한 등) |
dup(), dup2() | FD 복제 (리다이렉션에 필수) |
pipe() | 부모-자식 간 단방향 통신 (쉘의 ` |
unlink() | 파일 삭제 (디스크 공간 회수는 refcount=0일 때) |
🌐 2. 네트워크 관련 (소켓 기반)
시스템콜설명
socket() | 소켓 생성 (FD 반환) |
bind() | 소켓에 IP/PORT 할당 |
listen() | 수신 대기 설정 (서버용) |
accept() | 클라이언트 연결 수락 (새 FD 생성) |
connect() | 클라이언트에서 서버 연결 시도 |
send() / recv() | TCP 소켓에서 데이터 송수신 |
read() / write() | 소켓 FD에도 사용 가능 (send/recv와 유사) |
shutdown() | 소켓 연결의 특정 방향 종료 |
close() | 소켓 FD 닫기 |
🧵 3. 프로세스 및 스레드
시스템콜설명
fork() | 프로세스 복제 (자식 프로세스 생성) |
exec() 계열 | 다른 프로그램으로 현재 프로세스 덮어쓰기 |
wait() / waitpid() | 자식 프로세스 종료 대기 |
exit() | 현재 프로세스 종료 |
getpid() / getppid() | 현재 / 부모 프로세스 ID 조회 |
clone() | 리눅스 스레드 생성 (pthread 기반) |
🧠 4. 메모리/자원 관련
시스템콜설명
brk() / sbrk() | 힙 메모리 영역 조절 (구형 방식) |
mmap() / munmap() | 파일/메모리를 프로세스 주소 공간에 매핑 |
mprotect() | 메모리 접근 권한 변경 |
mlock() / munlock() | 메모리를 스왑 불가능하게 고정 |
getrlimit() / setrlimit() | FD 수 제한 등 자원 제한 설정 |
🕳️ 5. 기타 (디버깅, 성능, 제어)
시스템콜설명
select() / poll() / epoll_wait() | 여러 FD 동시 감시 (비동기 I/O 이벤트) |
nanosleep() | 고해상도 시간 지연 |
time() / gettimeofday() | 현재 시간 조회 |
ioctl() | 장치나 파일에 특수 명령 전달 |
kill() | 프로세스에 시그널 전송 |
getcwd() / chdir() | 현재 작업 디렉토리 조회/변경 |
✅ 실무에서 특히 중요한 핵심 Top 10
카테고리시스템콜
파일 I/O | open, read, write, fsync |
FD 조작 | dup2, pipe, close |
네트워크 | socket, bind, accept, connect |
비동기 | select, epoll_wait |
프로세스 | fork, exec, wait |
'개발기술 > 운영체제 핵심개념' 카테고리의 다른 글
POSIX multiplexing (3) | 2025.07.08 |
---|---|
POSIX I/O와 스트림 (0) | 2025.05.16 |
운영체제의 표준화 : POSIX와 시스템 콜 (0) | 2025.05.16 |
Blocking / Non-Blocking I/O (0) | 2025.02.15 |