拋去所有的模組和各種定義的資料結構,對於一個沒看過這麼大工程的小白來說,太亂!亂的不要不要,光是各種資料結構的意義,就讓我要抓狂了。好吧,我並不是說它結構不好,相反我感覺程式碼寫的太棒了。 。就是一時間。 。接受不了。廢話不說了,讓煩惱開始吧,唉╮(╯▽╰)╭
第一點:ngx_cdecl
<code><span>int</span> ngx_cdecl main(<span>int</span> argc, <span>char</span> *<span>const</span> *argv);</code>
是的,就是這個ngx_cdecl,之前知道在源碼裡面有__cdecl和__dcstall等東西,在這兒的ngx_cdecl又是什麼,照理說是一樣的,但是查到定義後是這樣的:
<code><span>#<span>define</span> ngx_cdecl</span></code>
對,就是一個空的define,那它有啥用?當然有用,而且用得很好,要不怎麼說人家是好代碼呢,後路留的多好,避免以後填坑。 nginx中使用這個巨集是為了跨平台支持,方便調整函數呼叫方式。在遇到問題時,可以修改上面的定義為:
<code><span>#<span>define</span> ngx_cdecl stdcal</span></code>
要不怎麼說多看程式碼有好處呢,這就是思想啊。好了再解釋下cdecl和stdcall:
__cdecl:C Declaration的縮寫,表示C語言預設的函數呼叫方法:所有參數從右到左依序入棧,這些參數由呼叫者清除,稱為手動清棧。被呼叫函數不會要求呼叫者傳遞多少參數,呼叫者傳遞過多或過少的參數,甚至完全不同的參數都不會產生編譯階段的錯誤。
呼叫函數的程式碼和被調函數必須採用相同的函數的呼叫約定,程式才能正常運作。
__cdecl和__stdcall的差別:__cdecl是呼叫者清理參數所佔用的堆疊,__stdcall是被調函數清理參數所佔用的堆疊。假設函數A是__stdcall,函數B呼叫函數A。你必須透過函數宣告告訴編譯器,函數A是__stdcall。編譯器自然會產生正確的呼叫程式碼。如果函數A是__stdcall,但在引用函數A的地方,你卻告訴編譯器,函數A是__cdecl方式,編譯器產生__cdecl方式的程式碼,與函數A的呼叫約定不一致,就會發生錯誤。
注意事項:由於__stdcall的被調函數在編譯時就必須知道傳入參數的準確數目(被調函數要清理堆疊),所以無法支援變參數函數,例如printf。而且如果呼叫者使用了不正確的參數數目,會導致堆疊錯誤。
第二點ngx_int_t & ngx_uint_t
<code><span>typedef</span> intptr_t ngx_int_t; <span>typedef</span> uintptr_t ngx_uint_t;</code>
在stdint.h中找到intptr的定義:
<code><span>117</span><span>/* Types for `void *' pointers. */</span><span>118</span><span>#<span>if</span> __WORDSIZE == 64 </span><span>119</span><span># ifndef __intptr_t_defined </span><span>120</span> typedef <span>long</span><span>int</span> intptr_t; <span>121</span><span># <span>define</span> __intptr_t_defined </span><span>122</span><span># <span>endif</span></span><span>123</span> typedef unsigned <span>long</span><span>int</span> uintptr_t; <span>124</span><span>#<span>else</span></span><span>125</span><span># ifndef __intptr_t_defined </span><span>126</span> typedef <span>int</span> intptr_t; <span>127</span><span># <span>define</span> __intptr_t_defined </span><span>128</span><span># <span>endif</span></span><span>129</span> typedef unsigned <span>int</span> uintptr_t; <span>130</span><span>#<span>endif</span></span></code>
定義中的註解說明,這兩個類型是定義用來當作指標使用的,因為指標的長度和長整數一直是一樣的,由於指標就是數組索引的存在,系統核心在操作記憶體時,就是將記憶體當作一個大數組,而指標就是數組索引/下標,核心程式設計師使用這種特殊的整型來接受記憶體位址值、操作記憶體相比使用指標更直觀,不容易犯錯。
intptr_t 這個型別可以被安全的在 void * 和 整數間轉換,對於寫跨 64 位元平台的程式非常重要。也就是說,當你需要把指標當作一個整數來運算時,轉換成 intptr_t 才是安全的,可以在運算完畢安全的轉回指標類型,也避免了對指標解引用產生的bug。
由程式碼中的巨集可以看出,intptr_t的長度是適應不同平台的,當編譯環境是64位元時,intptr_t是long int,否則就是int。
那麼nginx中使用它來typedef出ngx_int_t是想要乾嗎?為啥不用int來?
從型別名來看很容易理解為普通的int型,我想nginx使用它是因為intptr在定義的時候就自適應平台,根據平台來變化自己的長度,作者就不用自己再定義一次了。
以上就介紹了nginx原始碼初讀(1)--還是讓煩惱從main開始吧,包括了方面的內容,希望對PHP教程有興趣的朋友有所幫助。