[C언어] 12.함수 응용
C언어 학습 노트 : 12. 함수 응용#
1. 매개변수 전달 방식#
32비트 환경(x86)
- 대부분의 ABI에서 스택을 통해 인자를 전달한다.
- 오른쪽에서 왼쪽 순서로 스택에 푸시(push)된다.
- 호출자(caller)가 스택을 정리하는 규약(cdecl 등)과 피호출자(callee)가 정리하는 규약(stdcall 등)이 있다.
64비트 환경(x86-64, SysV, Windows)
주요 인자는 레지스터로 전달된다.
- SysV (리눅스): RDI, RSI, RDX, RCX, R8, R9 → 이후는 스택
- MS ABI (윈도우): RCX, RDX, R8, R9 → 이후는 스택
나머지는 스택에 전달된다.
2. Call by Value (값 호출)#
- 함수에 값의 복사본을 전달한다.
- 함수 내부에서 값이 변경되어도 원본에는 영향을 주지 않는다.
3. Call by Reference (참조 호출)#
- C 언어는 직접적인 참조 호출을 지원하지 않으며, 포인터를 전달하는 방식으로 구현한다.
- 주소를 넘겨줌으로써 함수 내부에서 원본 데이터를 수정할 수 있다.
- 설계 시 메모리 관리(수명, 해제 책임 등)를 명확히 고려해야 한다.
4. 재귀 호출#
- 함수가 자기 자신을 호출하는 구조.
- 기저 조건(base case) 을 반드시 명시하여 무한 재귀에 빠지지 않도록 해야 한다.
- 재귀 호출은 스택 프레임을 계속 쌓기 때문에, 깊이가 깊으면 스택 오버플로우가 발생한다.
- 따라서 입력 크기와 재귀 깊이를 고려해야 한다.
5. 스택 프레임과 지역 변수 주소 반환#
- 함수 호출 시 스택 프레임에는 반환 주소, 매개변수, 지역 변수가 저장된다.
- 함수가 종료되면 스택 프레임은 해제(pop)되며, 지역 변수의 주소는 더 이상 유효하지 않다.
- 따라서 지역 변수의 주소를 반환하면 정의되지 않은 동작(UB) 이 발생한다.
- 스택 메모리는 해제되지만 값이 즉시 덮어씌워지는 것은 아니므로, “쓰레기 값"이 남아 보이는 문제가 생길 수 있다.
6. 메모리 동적 할당과 관리 이슈#
malloc으로 메모리를 할당하고free로 해제하는 책임을 누가 가지는지 호출자와 피호출자 간 명확히 정의해야 한다.- 함수가 메모리를 할당하여 반환한다면, 이를 받은 쪽에서 해제해야 한다.
- 반대로 호출자가 메모리를 할당해 전달하면, 함수는 그 안에서만 사용하고 해제는 하지 않는다.
- 문서화와 명확한 인터페이스 정의가 필수적이다.
- 또한 메모리 크기를 알 수 없는 경우 사고가 발생할 수 있으므로, 크기도 함께 전달하는 것이 안전하다.
7. 스택 프레임 손상 문제#
C 언어에서는 버퍼 오버플로우가 발생할 수 있다.
지역 배열에 크기보다 더 큰 데이터를 저장하면, 스택에 이미 존재하는 다른 데이터(반환 주소 등)를 덮어쓸 수 있다.
이를 스택 프레임 손상(stack smashing) 이라 하며, 보안 취약점으로 악용될 수 있다.
방지 기법:
- 안전한 함수 사용 (
strcpy대신strncpy등) - 컴파일러 옵션 (Stack Protector, ASLR)
- 정적 분석/런타임 검사 도구 활용
- 안전한 함수 사용 (
학습 포인트 정리#
- 32비트는 스택 기반, 64비트는 레지스터 + 스택 혼합 기반으로 매개변수를 전달한다.
- 값 호출은 복사본을, 참조 호출은 포인터를 통해 원본을 수정한다.
- 재귀 호출은 기저 조건이 필수이며, 깊은 호출은 스택 오버플로우 위험을 가진다.
- 지역 변수 주소 반환은 금지된다.
- 동적 메모리 관리에서 할당/해제 책임은 반드시 문서화해야 한다.
- 버퍼 오버플로우는 스택 프레임을 손상시키므로 항상 주의해야 한다.