Throw away all the modules and various defined data structures. For a novice who has never seen such a large project, it is too messy! It’s so messy, just the meaning of various data structures drives me crazy. Well, I'm not saying it's poorly structured, on the contrary I feel the code is fantastic. . Just for a while. . Can't accept it. Stop talking nonsense and let the troubles begin, alas╮(╯▽╰)╭
The first point: ngx_cdecl
<code><span>int</span> ngx_cdecl main(<span>int</span> argc, <span>char</span> *<span>const</span> *argv);</code>
Yes, it is this ngx_cdecl. I knew before that there are things like __cdecl and __stdcall in the source code. What is ngx_cdecl here? Logically speaking, it is the same, but after looking up the definition, it is like this:
<code><span>#<span>define</span> ngx_cdecl</span></code>
Yes, it is an empty define, so what is its use? Of course it is useful, and it is used very well. Otherwise, how can we say that it is good code? It is great to leave a way out to avoid filling holes in the future. This macro is used in nginx for cross-platform support and to facilitate adjustment of function calling methods. When you encounter a problem, you can modify the above definition to:
<code><span>#<span>define</span> ngx_cdecl stdcal</span></code>
How about saying that reading more code is beneficial, this is the idea. Okay, let’s explain cdecl and stdcall:
__cdecl: The abbreviation of C Declaration, indicating the default function calling method of C language: all parameters are pushed onto the stack from right to left. These parameters are cleared by the caller, which is called manual stack clearing. The called function does not require the caller to pass how many parameters. The caller passes too many or too few parameters, or even completely different parameters, without causing a compile-time error.
The code calling the function and the called function must use the same function calling convention for the program to run normally.
The difference between __cdecl and __stdcall: __cdecl is the stack occupied by the caller cleaning parameters, and __stdcall is the stack occupied by the called function cleaning parameters. Suppose function A is __stdcall and function B calls function A. You must tell the compiler through the function declaration that function A is __stdcall. The compiler will naturally generate the correct calling code. If function A is __stdcall, but when you reference function A, you tell the compiler that function A is in __cdecl mode, and the compiler generates code in __cdecl mode that is inconsistent with the calling convention of function A, and an error will occur.
Note: Since the called function of __stdcall must know the exact number of parameters passed in during compilation (the called function must clear the stack), variable parameter functions such as printf cannot be supported. And if the caller uses an incorrect number of parameters, a stack error will result.
Second point ngx_int_t & ngx_uint_t
<code><span>typedef</span> intptr_t ngx_int_t; <span>typedef</span> uintptr_t ngx_uint_t;</code>
Find the definition of intptr in stdint.h:
<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>
The comments in the definition indicate that these two types are defined to be used as pointers, because the length of the pointer and The long integer type has always been the same. Since the pointer is an array index, the system kernel treats the memory as a large array when operating the memory, and the pointer is the array index/subscript. Kernel programmers use this special integer It is more intuitive to accept the memory address value and operate the memory than using pointers, and it is not easy to make mistakes.
intptr_t This type can be safely converted between void * and integer, which is very important for writing programs across 64-bit platforms. In other words, when you need to operate a pointer as an integer, it is safe to convert it to intptr_t. You can safely convert it back to the pointer type after the operation is completed, and avoid bugs caused by dereferencing the pointer.
As can be seen from the macros in the code, the length of intptr_t is adapted to different platforms. When the compilation environment is 64-bit, intptr_t is long int, otherwise it is int.
So why do you want to use it to typedef ngx_int_t in nginx? Why not use int?
Judging from the type name, it is easy to understand that it is an ordinary int type. I think nginx uses it because intptr adapts to the platform when it is defined and changes its length according to the platform, so the author does not need to define it again.
The above introduces the first reading of nginx source code (1) - let's start from the main, including the content, I hope it will be helpful to friends who are interested in PHP tutorials.