GNU C의 커다란 특성(초보자가 알기 쉽지 않지만) 중 하나는 속성(__attribute__)체계이다. __attribute__는 함수속성(Function attribute) 변수속성(Variable attribute) 그리고 타입속성(Type attribute)로 구분 된다. __attribute__의 표현 방식은 attribute의 앞과 뒤에 각각 두개씩의 아래바(__)를 붙이고 바로 이어 괄호안에 속성 인자를 쓰도록 되어있다.
1. 함수속성 (Function Atrribute)
참조 : http://gcc.gnu.org/onlinedocs/gcc-4.6.1/gcc/Function-Attributes.html#Function-Attributes
GNU C에서 프로그램에서 불리워질 함수들에 대해 컴파일러로 하여금 더욱 주의하여 최적화하고 검사하도록 선언할 수 있다. __attribute__는 우리가 함수를 선언할 때 특별한 속성을 부여할 수 있다. 이 __atribute__ 다음에는 쌍괄호로 싸여진 속성인자가 따라온다.
우리는 다음의 속성 키워드의 앞뒤에 __을 붙여 사용할 수 있다. 이는 같은 이름으로 정의된 매크로들에 상관없이 헤더파일에서 이 키워드들을 사용할 수 있게 해준다.
alias ("target")
alias 속성은 함수의 선언이 이미 명기된 다른 심볼에 대한 알리아스를 발생하도록 한다. 예를 들어,
void __f() { /* Do something. */ ; }
void f() __attribute__((weak, alias("__f")));
'f'를 '__f'에 대한 약한 알리아스로 정의한다.
aligned(alignment)
이 속성은 함수에 대한 최소정렬을 바이트 단위로 명기한다.
함수의 정렬을 감소시키기 위해 이 속성을 사용할 수 없고 단지 증가를 위해서만 사용가능하다. 하지만 함수에 대한 정렬을 명기했을 경우 -falign-functions 옵션의 효력은 사라지게 된다.
aligned 속성에 의한 효과는 링커(linker)에 의해 제한될 수 있다. 많은 시스템에서 함수는 링커가 제공하는 최대 정렬값까지 정렬될 수 있다. (어떤 링커는 최대 정렬값이 매우 매우 매우 작다.) aligned 속성은 변수에도 사용될 수 있다. (Variable Attribute 참조)
alloc_size
always_inline
gnu_inline
artifical
bank_switch
flatten
error("message")
warning("message")
cdecl
인텔 386 시스템에서 cdecl 속성은 컴파일러로 하여금 함수 인자를 전달하기 위해 사용했던 스택공간을 호출함수가 정리(pop off)할 것으로 가정하게 한다. 이는 -mrtd 스위치 효과를 덮어씌우기 위해 사용될 수 있다.
const
constructor
destructor
constructor(priority)
destructor(priority)
deprecated
deprecated(msg)
disinterrupt
dllexport
dllimport
eightbit_data
exception_handler
externelly_visible
far
fast_interrupt
fastcall
인텔 396 시스템에서 fastcall 속성은 컴파일러로 하여금 함수의 첫째 인자는 ECX를 통해 두 번째 인자는 EDX를 통해 전달하게 한다. 이어지는 더 많은 인자들은 스택을 통해 전달한다. 스택의 인자값들은 호출된 함수에서 정리(pop off) 한다. 만약 함수에 전달되는 인자수가 가변적이라면 모든 인자들은 스택을 통해 전달된다.
thiscall
인텔 386 시스템에서 thiscall 속성은 컴파일러로 하여금 함수의 첫째 인자는 ECX를 통해 전달하게 한다. 이어지는 다른 인자들은 스택을 통해 전달한다. 스택값은 호출된 함수에서 정리(pop off)된다. 전달되는 함수 인자 수가 가변적이면 모든 인자들은 스택을 통해 전달된다. thiscall 속성은 C++ non-static member 함수를 위한 것이다.
format( archetype, string-index, first-to-check )
format 속성은 함수가 printf, scant, strftime, strfmon 등과 같은 함수 인자 스타일을 갖음을 명기함으로써 포맷 문자열에 대해 typecheck가 이루어지게 한다. 예를 들어
extern int
my_printf(void *my_object, const char *my_format, ... )
__attribute__((format (printf, 2, 3)));
위 선언은 컴파일러로 하여금 my_printf를 호출하기 위해 함수인자인 my_format이 printf 형식의 포맷 문자열로서 모순이 없는지를 체크하게 한다.
파라메터 archetype은 포맷 문자열을 해석할 방식을 결정하는데 printf, scant, strftime, gnu_printf, gnu_scanf, gnu_strftime, strfmon 중에 하나이어야 한다. 파라메터 string-index는 어떤 함수인자가 포맷 문자열인지를 가리키며 first-to-check는 문자열에 대해 체크해 나갈 첫 함수인자의 번호이다. 한가지 용례로 아래의 test.c 프로그램을 보자.
1:
2: extern void myprint(const char *format, ...) __attribute__((format(print, 1, 2)));
3:
4: void test()
5:{
6: myprint("%d\n", 4);
7: myprint("%s\n", 4);
8: myprint("%s\n", "abc");
9: myprint("%s %d %d\n", 4, 6);
10:}
$gcc -Wall -c test.c test를 수행하면 다음과 같은 경고가 나타난다.
test.c: In function 'test'
test.c:7: warning: format '%d' expects type 'int', but argument 2 has type 'char *'
test.c:9: warning: format '%s' expects type 'char *', but argument 2 has type 'int'
test.c:9: warning: toot few arguments for format
만약 함수 선언중 _attribute__(()) 부분을 없애버리면 위의 경고문구는 사라지게 된다.
format_arg(string-index)
function_vector
interrupt
ifunc
interrupt_handler
interrupt_thread
isr
kspisusp
l1_text
l2
leaf
long_call/short_call
longcall/shortcall
long_call/near/far
malloc
mips16/nomips16
model(model-name)
ms_abi/sysv_abi
callee_pop_aggregate_return(number)
ms_hook_prologue
naked
near
nesting
nmi_handler
no_instrument_function
no_split_stack
noinline
noclone
nonull(arg-index, ...)
noreturn
abort 나 exit 같은 몇몇 표준 라이브러리 함수들은 반환할 수 없다. GCC는 자동으로 이를 안다. 어떤 프로그램들은 함수가 반환하지 않음을 자체적으로 정의할 수 있다. 우리는 noreturn을 선언함으로써 이를 컴파일러에게 일러줄 수 있다.
void fatal() __attribute__((noreturn));
void fatal( /* ... */ )
{
/* ... */ /* Print error message. */ /* ... */
exit(1);
}
noreturn 키워드는 컴파일러에게 fatal 함수가 반환할 수 없음을 일러준다. 그러면 이 fatal 함수가 무엇을 반환하려 하든 관계없이 최적화할 수 있다. 이는 조금 나은 코드를 만들게 하며 더 중요한 것은 초기화되지 않은 변수들에 대해 애매한 경고를 하지 않게 한다.
noreturn 함수가 void 이외의 타입을 갖는 것은 더 이상 의미가 없게 된다.
nothrow
optimize
pcs
pure
hot
cold
regparm(number)
인텔 386 시스템에서 regparm 속성은 컴파일러로 하여금 첫 번째 함수 인자로부터 number 번째 인자를 스택이 아닌 EAX, EDX ECX 등의 레지스터를 통해 전달하게 한다.
sseregparm
force_align_arg_pointer
resbank
return_twice
saveall
save_volatiles
section("section-name")
컴파일러가 생성한 코드는 text 영역에 두는 것이 정상적이다. 그러나 종종 추가적인 영역이 필요하거나 특별한 영역에 두어야 할 특별한 함수를 갖게 되는 경우가 있다. section 속성은 임의의 함수가 특정 영역에 있어야 함을 명기한다. 예를 들어
extern void foobar(void) __attribute__((section("bar")));
와 같이 선언하면 이는 함수 foobar를 bar 영역에 두라는 이야기이다.
어떤 파일형식은 임의의 영역을 지원하지 않으므로 section 속성은 모든 플랫폼에서 이용가능한 것은 아니다. 만약 한 모듈의 모든 내용을 하나의 영역에 두고자 한다면 링커를 이용할 수도 있다.
sentinel
short_call
shortcall
signal
sp_switch
stdcall
인텔 386 시스템에서 stdcall 속성은 컴파일러로 하여금 함수인자가 가변 개수가 아닌 이상은 인자를 전달하기 위해 사용한 스택영역을 호출된 함수에서 정리(pop off) 하는 것으로 가정하게 한다.
syscall_linkage
target
tiny_data
trap_exit
unused
used
version_id
visibility
vliw
warn_unused_result
weak
weakref
weakref("target")
2. 변수속성 (Variable Attribute)
참조 : http://gcc.gnu.org/onlinedocs/gcc-4.6.1/gcc/Variable-Attributes.html#Variable-Attributes
3. 타입속성 (Type Attribute)
참조 : http://gcc.gnu.org/onlinedocs/gcc-4.6.1/gcc/Type-Attributes.html#Type-Attributes