1. 程式人生 > >__attribute__((weak)) 用法

__attribute__((weak)) 用法

       情況是這樣的,碰到一個棘手的問題:我們不確定外部模組是否提供一個函式func,但是我們不得不用這個函式,即自己模組的程式碼必須用到func函式:

extern int func(void);
...................

int a = func();
if( a > .....)
{
..........
}
............

我們不知道func函式是否被定義了

這會導致2個結果:

1:外部存在這個函式func,並且EXPORT_SYMBOL(func),那麼在我自己的模組使用這個函式func,正確。

2:外部其實不存在這個函式,那麼我們使用func,程式直接崩潰。

所以這個時候,__attribute__((weak)) 派上了用場。

在自己的模組中定義:

int  __attribute__((weak))  func(......)
{
return 0;
}


將本模組的func轉成弱符號型別,如果遇到強符號型別(即外部模組定義了func),那麼我們在本模組執行的func將會是外部模組定義的func。

如果外部模組沒有定義,那麼,將會呼叫這個弱符號,也就是在本地定義的func,直接返回了一個1(返回值視具體情況而定)

相當於增加了一個預設函式。

原理:聯結器發現同時存在弱符號和強符號,有限選擇強符號,如果發現不存在強符號,只存在弱符號,則選擇弱符號。如果都不存在:靜態連結,恭喜,編譯時報錯,動態連結:對不起,系統無法啟動。 

注:
weak屬性只會在靜態庫(.o .a )中生效,動態庫(.so)中不會生效。


舉個例子:
strong.c  //生成libstrong.so

#include <stdio.h>
void real_func()
{
    printf("int real func\n");
}


weak.c //生成libweak.so

#include <stdio.h>
void real_func() __attribute__((weak));
void real_func()
{
    printf("fake func\n");
}

main.c //

#include <stdio.h>
extern void real_func();
void main()
{
        real_func();
}

如果 

gcc main.c -lstrong -lweak

那麼輸出結果"real func"。

如果 

gcc main.c -lweak -lstrong

那麼輸出結果為"fake func"。

可見,對於動態庫,weak屬性毫無作用,且main中呼叫哪個real_func(),取決於順序。

如果將strong.c 和 weak.c編譯成.a或者.o

gcc main.c strong.o weak.o

或者

gcc main.c weak.o strong.o

那麼輸出結果都是"real func"。

所以,如果在so中使用weak屬性,那麼任何不符合預期的情況,都是可能出現的。

官方解釋:
https://sourceware.org/bugzilla/show_bug.cgi?id=3946