本篇內(nèi)容介紹了“visibility屬性在cpython中的應(yīng)用方法是什么”的有關(guān)知識,在實(shí)際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
創(chuàng)新互聯(lián)建站-專業(yè)網(wǎng)站定制、快速模板網(wǎng)站建設(shè)、高性價(jià)比英吉沙網(wǎng)站開發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫,直接使用。一站式英吉沙網(wǎng)站制作公司更省心,省錢,快速模板網(wǎng)站建設(shè)找我們,業(yè)務(wù)覆蓋英吉沙地區(qū)。費(fèi)用合理售后完善,10多年實(shí)體公司更值得信賴。
GCC 的attribute語法可以為函數(shù),結(jié)構(gòu)體,類,枚舉, 變量,標(biāo)簽等添加屬性。 例如為函數(shù)添加屬性__attribute__((noreturn)),可以讓編譯器知道該函數(shù)不會返回給調(diào)用者,并作出相應(yīng)優(yōu)化。
在Windows專用修飾符中也有類似gcc attribute語法的關(guān)鍵字 —— __declspec. 在追求跨平臺通用性的時(shí)候,通常會同時(shí)加入gcc __attribute__ 和windows __declspec,在編譯時(shí)判斷平臺,決定使用哪一種方式
__declspec( 屬性 ) 聲明語句 // 舉例 __declspec( dllimport ) int i; __declspec( dllexport ) void func();
Q: __attribute__((屬性列表)) 到底寫在什么位置?
A: 相同作用對象添加不同屬性,或相同屬性作用于不同對象,有的緊跟關(guān)鍵字,有的在整個(gè)聲明之后。具體可查閱官方文檔
//可以緊跟在 struct, class, union, enum 關(guān)鍵字之后,也可以在右括號之后,首選前者 struct __attribute__ ((aligned (8))) S { short f[3]; }; //為結(jié)構(gòu)體S添加屬性 aligned (8) //在typdef聲明中使用 typedef int T1 __attribute__ ((deprecated)); //T1在任意地方被使用時(shí),deprecated屬性會產(chǎn)生告警 //函數(shù) __attribute__((屬性列表)) void foo1 (void); void foo2 (void) __attribute__((屬性列表));
Q: 有哪些屬性可以用?
A: 對于函數(shù),結(jié)構(gòu)體,類等不同的作用對象,都有各自支持的屬性,其中又分為最常用的公共屬性和針對特定CPU架構(gòu)的特殊屬性,詳情請查閱官方文檔。
visibility 屬性用于指定可見性,可以用于 函數(shù), class, struct, union, enum,使用語法一致。
void __attribute__ ((visibility ("protected"))) f () { /* Do something. */; } int i __attribute__ ((visibility ("hidden")));
屬性值:
default:具有外部鏈接性 (external linkage),可以被外部其它模塊引用,并且有可能被重寫
hidden:只能在同一共享對象(可簡單理解為庫文件)中被引用
internal:無法被其它模塊直接引用,但是可以通過指針間接引用
protected:可以被引用,但無法被重寫
在講visibility屬性用法之前 ,我們先了解一下,
__declspec( 屬性 ) 聲明語句 // 舉例 __declspec( dllimport ) int i; __declspec( dllexport ) void func();
此處我們看gcc wiki中的一例經(jīng)典模板,可以用于定義共享庫
/* 定義宏: 標(biāo)識符: FOX_HELPER_DLL_IMPORT default,指定函數(shù), class, struct 等為公開可重寫的。不編譯,直接導(dǎo)入。 標(biāo)識符: FOX_HELPER_DLL_EXPORT default,指定函數(shù), class, struct 等為公開可重寫的。編譯并導(dǎo)出為動態(tài)庫(DLL或so) 標(biāo)識符: FOX_HELPER_DLL_LOCAL hidden,指定函數(shù), class, struct 等只能在同一共享對象中被引用 */ /* 對于win32和Cygwin,使用__declspec()指定屬性 */ #if defined _WIN32 || defined __CYGWIN__ #define FOX_HELPER_DLL_IMPORT __declspec(dllimport) //從dll導(dǎo)入。其它模塊可見 #define FOX_HELPER_DLL_EXPORT __declspec(dllexport) //導(dǎo)出到dll。其它模塊可見 #define FOX_HELPER_DLL_LOCAL #else /*對于gcc,使用__attribute__ ((visibility ("屬性值"))) 指定可見性*/ #if __GNUC__ >= 4 #define FOX_HELPER_DLL_IMPORT __attribute__ ((visibility ("default"))) #define FOX_HELPER_DLL_EXPORT __attribute__ ((visibility ("default"))) #define FOX_HELPER_DLL_LOCAL __attribute__ ((visibility ("hidden"))) #else /*代碼中已經(jīng)引用了宏,即使什么屬性都不加,也要定義宏*/ #define FOX_HELPER_DLL_IMPORT #define FOX_HELPER_DLL_EXPORT #define FOX_HELPER_DLL_LOCAL #endif #endif /*定義宏 FOX_API 與 FOX_LOCAL 標(biāo)識符: FOX_API default,指定函數(shù), class, struct 等為公開可重寫的,要么編譯導(dǎo)出,要么直接導(dǎo)入 標(biāo)識符: FOX_LOCAL hidden,指定函數(shù), class, struct 等只能在同一共享對象中被引用 */ #ifdef FOX_DLL // 如果FOX需要被編譯為動態(tài)庫 #ifdef FOX_DLL_EXPORTS // 如果是正在構(gòu)建 (而非使用) FOX #define FOX_API FOX_HELPER_DLL_EXPORT //導(dǎo)出動態(tài)庫 #else #define FOX_API FOX_HELPER_DLL_IMPORT //不構(gòu)建,直接導(dǎo)入動態(tài)庫 #endif // FOX_DLL_EXPORTS #define FOX_LOCAL FOX_HELPER_DLL_LOCAL //定義FOX_LOCAL #else // 沒有定義 FOX_DLL 宏,則說明FOX是靜態(tài)庫,不添加任何屬性 #define FX_API #define FOX_LOCAL #endif // FOX_DLL
引用方式:
//聲明一個(gè)公開可重寫(default)的函數(shù) extern FOX_API PublicFunc1(); //extern __attribute__ ((visibility ("default"))) PublicFunc1(); //聲明一個(gè)僅內(nèi)部使用(hidden)的函數(shù) extern FOX_LOCAL PublicFunc2(); //extern __attribute__ ((visibility ("hidden"))) PublicFunc2(); //聲明一個(gè)公開可重寫(default)的類 class FOX_API PublicClass1; //class __attribute__ ((visibility ("default"))) PublicClass1; //聲明一個(gè)僅內(nèi)部使用(hidden)的類 class FOX_LOCAL PublicClass2; //class __attribute__ ((visibility ("hidden"))) PublicClass2;
研究過cpython的朋友看到以上demo可能會有點(diǎn)眼熟。是的,cpython中有一段相似的代碼。當(dāng)然,cpython中還兼容了clang。
#ifndef Py_EXPORTS_H #define Py_EXPORTS_H /* 定義宏: 標(biāo)識符: Py_IMPORTED_SYMBOL default,指定函數(shù), class, struct 等為公開可重寫的。不編譯,直接導(dǎo)入 標(biāo)識符: Py_EXPORTED_SYMBOL default,指定函數(shù), class, struct 等為公開可重寫的。編譯導(dǎo)出到動態(tài)庫(DLL或so) 標(biāo)識符: Py_LOCAL_SYMBOL hidden,指定函數(shù), class, struct 等只能在同一共享對象中被引用 */ /* 對于win32和Cygwin,使用__declspec()指定屬性 */ #if defined(_WIN32) || defined(__CYGWIN__) #define Py_IMPORTED_SYMBOL __declspec(dllimport) //從dll導(dǎo)入。其它模塊可見 #define Py_EXPORTED_SYMBOL __declspec(dllexport) //導(dǎo)出到dll。其它模塊可見 #define Py_LOCAL_SYMBOL #else //__has_attribute參數(shù)為屬性名,可以評估當(dāng)前編譯目標(biāo)是否支持該屬性,支持為1,不支持為0 //下面三行代碼用于兼容non-clang編譯器。對于non-clang編譯器,__has_attribute(x)表達(dá)式直接轉(zhuǎn)0 #ifndef __has_attribute #define __has_attribute(x) 0 #endif //如果 gcc版本>=4 或 clang判定編譯目標(biāo)支持visibility屬性,則添加屬性 #if (defined(__GNUC__) && (__GNUC__ >= 4)) || (defined(__clang__) && __has_attribute(visibility)) #define Py_IMPORTED_SYMBOL __attribute__ ((visibility ("default"))) #define Py_EXPORTED_SYMBOL __attribute__ ((visibility ("default"))) #define Py_LOCAL_SYMBOL __attribute__ ((visibility ("hidden"))) #else #define Py_IMPORTED_SYMBOL #define Py_EXPORTED_SYMBOL #define Py_LOCAL_SYMBOL #endif #endif #endif /* Py_EXPORTS_H */
Py_LOCAL_SYMBOL
:在源碼之中暫未發(fā)現(xiàn)引用之處
Py_IMPORTED_SYMBOL
:用于在Windows編譯器或cygwin中,構(gòu)建非核心模塊時(shí)定義宏 PyAPI_FUNC
,PyAPI_DATA
,意義是直接導(dǎo)入核心模塊,防止編譯器再次編譯。原因參考此處。
Py_EXPORTED_SYMBOL
:定義宏 PyAPI_FUNC
,PyAPI_DATA
, PyMODINIT_FUNC
以下代碼中會用到的一些宏標(biāo)識符,先進(jìn)行一下說明:
Py_ENABLE_SHARED
值為1 ,windows平臺下,Python核默認(rèn)在DLL中,允許外部鏈接性
HAVE_DECLSPEC_DLL
所有windows編譯器和cygwin均會定義,用于支持__declspec().
Py_BUILD_CORE
構(gòu)建Python內(nèi)核。提供對Python內(nèi)部構(gòu)件的訪問權(quán),但不應(yīng)被第三方模塊使用。
Py_BUILD_CORE_MODULE
構(gòu)建一個(gè)Python stdlib模塊作為一個(gè)動態(tài)庫,Windows上導(dǎo)出“PyInit_xxx”符號。
/*不同平臺構(gòu)建的差異請參考:https://docs.python.org/zh-cn/3/extending/windows.html#a-cookbook-approach*/ /* 首先處理windows平臺及cygwin */ #if defined(Py_ENABLE_SHARED) || defined(__CYGWIN__) # if defined(HAVE_DECLSPEC_DLL) //構(gòu)建Python內(nèi)核,而非Python stdlib模塊 # if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) # define PyAPI_FUNC(RTYPE) Py_EXPORTED_SYMBOL RTYPE # define PyAPI_DATA(RTYPE) extern Py_EXPORTED_SYMBOL RTYPE //核心模塊初始化函數(shù)不需要外部鏈接性,除非Cygwin來處理嵌入 # if defined(__CYGWIN__) # define PyMODINIT_FUNC Py_EXPORTED_SYMBOL PyObject* # else /* __CYGWIN__ */ # define PyMODINIT_FUNC PyObject* # endif /* __CYGWIN__ */ # else /* Py_BUILD_CORE */ //核心構(gòu)建結(jié)束,接下來構(gòu)建擴(kuò)展模塊(非核心模塊)或嵌入式環(huán)境,需要先導(dǎo)入公共函數(shù)及數(shù)據(jù) //使用cygwin會自動導(dǎo)入公共函數(shù)防止編譯,如果沒用使用cygwin,則需顯式導(dǎo)入 # if !defined(__CYGWIN__) # define PyAPI_FUNC(RTYPE) Py_IMPORTED_SYMBOL RTYPE # endif /* !__CYGWIN__ */ # define PyAPI_DATA(RTYPE) extern Py_IMPORTED_SYMBOL RTYPE //按C語言的語法,編譯導(dǎo)出非核心模塊的初始化函數(shù) # if defined(__cplusplus) # define PyMODINIT_FUNC extern "C" Py_EXPORTED_SYMBOL PyObject* # else /* __cplusplus */ # define PyMODINIT_FUNC Py_EXPORTED_SYMBOL PyObject* # endif /* __cplusplus */ # endif /* Py_BUILD_CORE */ # endif /* HAVE_DECLSPEC_DLL */ #endif /* Py_ENABLE_SHARED */ /*如果任然未定義PyAPI_FUNC, PyAPI_DATA, PyMODINIT_FUNC, 說明不是windows平臺或cygwin。默認(rèn)采用gcc方式定義*/ #ifndef PyAPI_FUNC //__attribute__ ((visibility ("default"))) RTYPE # define PyAPI_FUNC(RTYPE) Py_EXPORTED_SYMBOL RTYPE #endif #ifndef PyAPI_DATA //extern __attribute__ ((visibility ("default"))) RTYPE # define PyAPI_DATA(RTYPE) extern Py_EXPORTED_SYMBOL RTYPE #endif //無論是核心還是非核心模塊,都需要外部鏈接性 #ifndef PyMODINIT_FUNC # if defined(__cplusplus) //extern "C" __attribute__ ((visibility ("default"))) PyObject* # define PyMODINIT_FUNC extern "C" Py_EXPORTED_SYMBOL PyObject* # else /* __cplusplus */ //__attribute__ ((visibility ("default"))) PyObject* # define PyMODINIT_FUNC Py_EXPORTED_SYMBOL PyObject* # endif /* __cplusplus */ #endif
注:以上說的Windows平臺/編譯器,默認(rèn)指Microsoft Visual C++,但理論上其它編譯器也可以支持
今天研究的是gcc,接下來按照gcc處理方式分析PyAPI_FUNC
, PyAPI_DATA
, PyMODINIT_FUNC
是如何使用的。
PyAPI_FUNC
以pycore_hashtable.h
中的_Py_hashtable_compare_direct方法為例
extern "C" PyAPI_FUNC(int) _Py_hashtable_compare_direct {//函數(shù)體略};
根據(jù)define的使用方法替換一下,此處就相當(dāng)于
extern "C" Py_EXPORTED_SYMBOL int _Py_hashtable_compare_direct {//函數(shù)體略};
繼續(xù)替換
extern "C" __attribute__ ((visibility ("default"))) int _Py_hashtable_compare_direct {//函數(shù)體略};
到這一步我們就清晰了,這里其實(shí)是定義了一個(gè)公開的可以被其它模塊調(diào)用或重寫的函數(shù)int _Py_hashtable_compare_direct
結(jié)論:PyAPI_FUNC
指定函數(shù)可以被各個(gè)模塊訪問。
PyAPI_DATA
以boolobject.h
中的PyBool_Type
為例
PyAPI_DATA(PyTypeObject) PyBool_Type; //PyTypeObject是一個(gè)結(jié)構(gòu)體
替換
extern Py_EXPORTED_SYMBOL PyTypeObject PyBool_Type;
繼續(xù)替換
extern __attribute__ ((visibility ("default"))) PyTypeObject PyBool_Type;
結(jié)果是聲明了一個(gè)可以被其它模塊訪問的PyTypeObject結(jié)構(gòu)體變量。
結(jié)論:PyAPI_DATA
指定變量可以被其它模塊訪問
PyMODINIT_FUNC
以arraymodule.h
的中的模塊初始化函數(shù)為例
PyMODINIT_FUNC PyInit_array(void) { return PyModuleDef_Init(&arraymodule); }
替換
//c語言 Py_EXPORTED_SYMBOL PyObject* PyInit_array(void) { return PyModuleDef_Init(&arraymodule); } //C++ extern "C" Py_EXPORTED_SYMBOL PyObject* PyInit_array(void) { return PyModuleDef_Init(&arraymodule); }
到這里可以看出來,PyInit_array()
函數(shù)調(diào)用了PyModuleDef_Init()
方法對arraymodule
進(jìn)行了初始化,然后然返回一個(gè)PyObject
結(jié)構(gòu)體的指針變量
繼續(xù)替換
//c語言 __attribute__ ((visibility ("default"))) PyObject* PyInit_array(void) { return PyModuleDef_Init(&arraymodule); } //C++ extern "C" __attribute__ ((visibility ("default"))) PyObject* PyInit_array(void) { return PyModuleDef_Init(&arraymodule); }
結(jié)果是定義了一個(gè)其它模塊可以訪問的模塊初始化函數(shù),用于初始化arraymodule
,并返回PyObject
結(jié)構(gòu)體的指針變量
結(jié)論:PyMODINIT_FUNC
指定模塊初始化函數(shù)可以被其它模塊訪問,并返回PyObject
結(jié)構(gòu)體的指針變量
GCC 的attribute語法可以為函數(shù),結(jié)構(gòu)體,類,枚舉, 變量,標(biāo)簽等添加屬性。語法:
__attribute__ ((屬性列表))
位置一般在關(guān)鍵字之后,或整個(gè)聲明之后,具體查閱官方文檔
visibility屬性
extern __attribute__ ((visibility ("default"))) PublicFunc1(); class __attribute__ ((visibility ("default"))) PublicClass1;
default:具有外部鏈接性 (external linkage),可以被外部其它模塊引用,并且有可能被重寫
hidden:只能在同一共享對象(可簡單理解為庫文件)中被引用
internal:無法被其它模塊直接引用,但是可以通過指針間接引用
protected:可以被引用,但無法被重寫
visibility屬性實(shí)際應(yīng)用之cpython
PyAPI_FUNC
:指定函數(shù)可以被各個(gè)模塊訪問
PyAPI_DATA
: 指定變量可以被其它模塊訪問
PyMODINIT_FUNC
: 指定模塊初始化函數(shù)可以被其它模塊訪問,并返回PyObject
結(jié)構(gòu)體的指針變量
“visibility屬性在cpython中的應(yīng)用方法是什么”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!
文章標(biāo)題:visibility屬性在cpython中的應(yīng)用方法是什么
鏈接地址:http://aaarwkj.com/article44/igscee.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站制作、網(wǎng)站營銷、網(wǎng)站制作、定制開發(fā)、App開發(fā)、響應(yīng)式網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)