정해지지 않은 수의 매개변수(가변 인자)를 허용하는 함수
최소한 한개의 정해진 자료형의 매개변수가 필요하다.
ex. printf()
scanf()
같은 것
int add_ints(cont size_t count, ...){
va_list ap; // 가변 인자 목록, va_start(), va_arg(), va_end() 매크로 함수를 사용할 때 필요한 정보 포함
int sum;
size_t i;
sum = 0;
va_start(ap, count);
{
for (i = 0; i<count; i++){
sum += va_arg(ap, int);
}
}
va_end(ap);
return sum;
}
va_start()
va_end()
va_arg()
int
모든 실수형은 double
로printf()
함수에서 모든 실수형이 %f
서식으로 출력가능했던 이유와도 같다 (어차피 double
형으로 들어오니까)가변인자 함수도 호출시 매개변수를 입력하기 때문에 그 만큼 스택프레임에 넣어주면된다 (일반 함수와 동일)
BUT, 가변인자 함수 내에서 매개변수를 읽어올때 몇 개가 들어올지 알 수 없기 때문에 이 부분이 문제
첫 번째 매개변수의 위치와 자료형을 알기 때문에 데이터 접근 가능!
va_start(ap, count)
: 가변인자 시작전 마지막 데이터의 메모리 주소 계산
va_start(ap, count) // 코드
ap.data = (char*)&count + sizeof(count) // 매크로 내부 구현 예상 (전처리기가 변환할 코드)
va_arg(ap, int)
: int
크기만큼 더해가면서 읽을 위치를 변경
val = *(int*)ap.data++;
매크로함수?
C에는 예외처리가 없지만 가장 안정적인 프로그램들을 만든 언어 (운영체제)
예외처리가 반드시 소프트웨어 품질을 높이는 것은 아니다.
예외처리가 없는 언어에서 문제가 발생하면?
예외처리가 있는 언어라면 그냥 넘어갈 수 있다
예외처리의 유무보다 오류 상황을 대비하고 처리하는 전략이 중요하다.
스왑함수를 호출하는데 오류가 났다면?
// 원본
void swap (int* a, int* b){
int tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
주먹구구식 오류처리
// 주먹구구식 오류처리
void swap (int* a, int* b){
int tmp;
if(a==NULL || b==NULL){
return;
}
/* */
tmp = *a;
*a = *b;
*b = tmp;
}
이게 왜 문제인가
함수는 호출되었는데 NULL
이 들어와서 그냥 리턴한건지 제대로 실행된건지 사용자는 확인하기가 어렵다.
이런 식의 함수가 여러개라면? 문제가 생겼을 때 일일히 다 확인해봐야되는 문제
이 함수에 NULL
이 들어와도 되는가를 먼저 검증해야하지 않을까?
진짜 NULL
포인터가 허용되는 경우라면 함수나 변수이름에 명시하는 것도 좋다.
이렇게 하면 함수를 유지보수하거나 사용하는 사람도 오류확률을 줄일 수 있다.
moster_t* spawn_monster_or_null(const monster_t* special_monster_or_null)
문제는 한 군데서만 찾는게 더 효율적 (집중의 문제)
버그
assert
)오류
주어진 조건을 만족하는지 확인하는 함수 (버그 상황 확인)
만족하지 않으면 코어 덤프와 함께 오류메시지 출력하고 프로그램 종료
사용자에게 제공되는 프로그램의 실제 코드 내부에서는 제거해줘야한다.
unsigned int deposit (unsigned int deposit_amount){
unsigned int before_total;
unsigned int after_total;
assert(deposit_amount > 0); // 예금 금액이 0인 상황은 존재할 필요가 없다.
/* 코드 생략 */
assert(before_total < after_total);
return after_total;
}
- 기본적으로 내가 작성하는 모든 함수에 들어오는 데이터는 유효하다 가정하고 어서트를 많이 쓸 것
- 그렇지 않은 함수는 매개변수나 함수 이름에서 그렇지 않다는 사실을 명백히 표시할 것
- 오류 상황을 정리하는 부분은 최소한으로 할 것
- 어떤 함수가 오류 처리를 한다는 사실을 반환형을 통해 확실히 보여줄 것