See http://community.csdn.net/Expert/topic/3662/3662366.xml? Temp =. 1618006 there is a post about the excitement.
The specific question is what is the macro function, # define macro1 (T, m) (INT) (void *) & (T *) 0-> m ). Is to get the offset of T (structure or class) member m in the structure (or class. However, many people cannot understand (T *) 0-> M. I will analyze it. First write a program segment:
# Pragma pack (1)
Typedef struct {
Char;
Int B;
};
# Pragma pack ()
# Define macro1 (T, m) (INT) (void *) & (T *) 0)-> m)
Int main (INT argc, char * argv [])
{
A * pA = (A *) 0; // defines a pointer PA pointing to 0, but the type is *
Printf ("% P/N", PA); // The value is 0.
Void * pvoid = & PA; // obtain the address of PA. Although Pa = 0, its address is not 0.
Printf ("% P/N", pvoid); // print 0x12ff7c here.
Printf ("% P/N", & (Pa-> B); // print out 1
Printf ("% d/N", pa-> B); // Invalid Memory Access, error
Return 0;
}
What does it mean? & (Pa-> B) is equal to 1, and pa-> B is illegal access?
Next, let's see how the compiler works:
37: int main (INT argc, char * argv [])
38 :{
0040d960 push EBP
0040d961 mov EBP, ESP
0040d963 sub ESP, 48 h
0040d966 push EBX
0040d967 push ESI
0040d968 push EDI
0040d969 Lea EDI, [ebp-48h]
0040d96c mov ECx, 12 h
0040d971 mov eax, 0 cccccccch
0040d976 rep STOs dword ptr [EDI]
39:
40: A * pA = (A *) 0;
0040d978 mov dword ptr [ebp-4], 0 // put a 0 to PA pointer directly
41: printf ("% P/N", PA );
0040d97f mov eax, dword ptr [ebp-4]
0040d982 push eax
0040d983 push offset string "% P/N" (00422020)
0040d988 call printf (00401310)
0040d98d add ESP, 8
42: void * pvoid = & PA;
0040d990 Lea ECx, [ebp-4] // get pa address
0040d993 mov dword ptr [ebp-8], ECx
43: printf ("% P/N", pvoid );
0040d996 mov edX, dword ptr [ebp-8]
0040d999 push edX
0040d99a push offset string "% P/N" (00422020)
0040d99f call printf (00401310)
0040d9a4 add ESP, 8
44: printf ("% P/N", & (Pa-> B); // something we care about comes.
0040d9a7 mov eax, dword ptr [ebp-4] // gets the value pointed to by the PA pointer, 0
0040d9aa add eax, 1 // Add 1, which is the offset of B
0040d9ad push eax
0040d9ae push offset string "% P/N" (00422020)
0040d9b3 call printf (00401310)
0040d9b8 add ESP, 8
45: printf ("% d/N", pa-> B); // Why is this sentence incorrect?
0040d9bb mov ECx, dword ptr [ebp-4] // get pointer
0040d9be mov edX, dword ptr [ECx + 1] // Add 1 to the pointer first and then obtain its value, that is, the value of 0x00000001.
0040d9c1 push edX
0040d9c2 push offset string "% d/N" (0042201c)
0040d9c7 call printf (00401310)
0040d9cc add ESP, 8
46:
47:
48:
49: Return 0;
0040d9cf XOR eax, eax
...
Here we can see that the compiler does not care about the & (Pa-> B) in the->, but is very "intelligent" to get the address of B directly, because the PA address is 0, therefore, the address of B starts from 0, which is equivalent to computing from the beginning of the structure. The next pa-> B is to obtain the exact value of B. Of course, the compiler needs to retrieve data from the 0 + 1 address, however, this place cannot be accessed by any program at will, so an error occurs.