임베디드의 라이브러리를 파악하던 도중 특이한 것을 보았습니다.
바로 __attribute__((weak))입니다. 그동안 __attribute__는 함수에 대한 특성을 정하는 것이라고 들었을 뿐, 다른 것은 듣지 못했습니다.
그렇기에, 오늘 이에 대한 것을 알려드릴려고 합니다.
Weak Function이란?
Weak Function은 함수의 특성이 Weak인 것으로, 만일 같은 이름의 함수가 생성이 될 경우, __attribute__((weak))로 선언된 함수 부분은 컴파일 하였을 때, 제거가 되고, 새로 재정의된 함수가 Weak 함수의 자리를 대체합니다. 주로 임베디드 라이브러리에서도 자주 보이기도 하죠.
이를 이용한 대표적인 것이 임베디드에서의 ISR로 ISR같은 경우 함수의 특성이 weak와 alias("DefualtHandler")로 정의 되어있습니다.
예시
t1.h와 t1.c, 그리고 t2.c를 만들어봅시다.
t1.h는
#include <stdio.h>
#include <stdlib.h>
void ErrorHandler(void);
void firstFunction(void);
로 기본적인 함수들과 필요한 헤더들을 집어 넣었습니다.
t2.c는
#include "t1.h"
void ErrorHandler(void){
fputs("You Don't Make Functions", stderr);
fputc('\n', stderr);
exit(-1);
}
void __attribute__((weak, alias("ErrorHandler"))) firstFunction(void);
로 t1.h로부터 선언된 함수들에대한 정의를 하였고, 이곳에서 firstFunction같은 경우 weak symbol 특성을 부여함과 동시에, ErrorHandler을 별명으로 가지도록 했습니다.
즉 이름만 firstFunction인 실행은 ErrorHandler가 되는 함수가 되었습니다.
그럼 여기서 t2.c는 main함수 부분으로 다음과 같이 작성했습니다.
#include "1.h"
int main(void){
firstFunction();
}
testCall같은 경우 weak symbol 특성을 이해하기 위해 만든 것으로, firstFunction을 호출하는 함수입니다.
만일 이와 같이 작성하여 컴파일을 진행한다면, 어떤 결과가 나올까요?
이미 위에서 firstFunction의 또다른 별명은 ErrorHandler라고 작성을 하였기에, ErrorHandler에 있는 함수 내용이 작성됨을 알 수 있
습니다.
그럼 만약 t2.c에서 firstFunction을 재정의를 한다면 어떻게 될까요?
#include "t1.h"
int main(void){
testCall();
firstFunction();
}
void firstFunction(){
printf("Make Function Complete!!!!\n");
}
testCall은 t1.h에서 새로 작성한 함수로, Weak Function에 대한 이해를 위해 작성한 것입니다.
만약 실행을 한다면, 어떤 일이 발생할까요?
신기하게도 firstFunction은 재정의가 된 것으로 교체되었고, 무려 testCall마저 호출한 firstFunction이 재정의된 firstFunction으로 바뀌었음을 알 수 있습니다.
이를 통하여, weak function으로 선언 된 경우, 만약 같은 이름의 함수를 작성(재정의)를 한다면, weak 특성으로 만들어진 함수는 컴파일 과정에서 제거가 되고, 제거가 된 weak function은 재정의를 한 strong symbol을 가진 함수가 대체한다는 것을 알 수 있습니다
주의
__attribute__를 이용할 시에는 최대한 헤더파일에서 정의하지 않을 것을 추천합니다.