Customary method for acquiring structural field offset value in ANSI C

xiaoxiao2021-03-06  41

Suppose a struct type called MyStruct is defined in the ANSI C program, with a field named myfield, how to get the offset in the structure?

Typedef struct mystruct_tag {// Some Fields ...

Long myfield;

// taff.} mystruct;

The most easily thought of the way should be similar to the following code:

SIZE_T GETOFFSET () {mystruct S;

Return (Size_T) (& S.MYFIELD) - (CHAR *) (& S));

This code can do tasks, but in order to achieve offset values, the function has to define an instance of a MyStruct structure, can this be necessary? Think carefully, when is the memory layout of the structure? That's right, it is determined by the compiler in the compiler. Once it is determined, it will not change, but the field offset depending on the memory layout of the structure is not changed. Since the compilation phase compiler is insiders, then we have reason to request that it provides this information in the compile period. How to do it? Please see the following code:

#define my_offset (size_t) & ((mystruct *) 0) -> Myfield

The MY_OFFSET macro defined above is the offset of our Myfield. Some people must ask, how can the structural pointer after the conversion can be used to access the structural field? Oh, in fact, this expression is not not intended to access the Myfield field. The ANSI C standard allows for any value of 0 to be forced to convert to any type of pointer, and the conversion result is a NULL pointer, so the result of ((MyStruct *) 0) is a NULL pointer of a type mYStruct *. If you use this NULL pointer to access the mystruct, it is of course illegal, but & (((mystruct *) 0) -> myfield is not to access the Myfield field content, but only the first site of the structure instance The address of the Myfield field is ((mYStruct *) 0). The smart compiler does not generate the code that accesses myfield, but only calculates this (constant) address based on the MYSTRUCT's memory layout and structural instance, which completely avoids accessing memory through the NULL pointer. Also because the value of the first site is 0, the value of this address is the offset of the field relative to the base base.

If you do so, you must instantiate a MyStruct object, and the value is carried out in the compile period, no running period. In fact, this information on the entire program that is mastered with the compiler is similar to the method of calculating certain values ​​in compile period, and now is similar to the current (static) metad programming technology in C programming, only C programmers can use template technology to compile Complete a very complex calculation, while the ANSI C supported by template is weaker in this regard.

Perhaps because of the common use of structural field offset, ANSI C specializes in the standard header file stddef.h specifically defines a macro such as OFFSTOF (S, M) to request an offset of a field in a structure type. And the implementation of the vast majority of C-development systems use the above method, for example:

// vc7.1 # ifdef _win64 # define offsetof (s, m) (SIZE_T) ((ptrdiff_t) & (((S *) 0) -> M)) # Else # define offsetof (s, m) (size_t) & (((S *) 0) -> M) #ENDIF

// LCC-WIN32, Last Updated: Monday, 13-DEC-2004 04:05:23 EST # define Offsetof (S, M) (INT) & (((S *) 0) -> M) // Borland C 5.5.1 for Win32 # Define Offsetof (_Name, M_Name) (_Size_t) & ((S_Name_far *) 0) -> m_name)

// mingw 3.1.0 (GCC 3.2.3) #ifndef __cplusplus # define offsetof (type, member) ((SIZE_T) & ((TYPE *) 0) -> MEMBER #ELSE / * C * // * The Reference cast is necessary to thwart an operator & that might be applicable to MEMBER's type. See DR 273 for details. * / # define offsetof (tYPE, MEMBER) (reinterpret_cast / (& reinterpret_cast (static_cast ( 0) -> Member)) # ENDIF / * C * /

It can be seen that this simple and effective method has been accepted as a customary method (iDiom) by the C programmer.

转载请注明原文地址:https://www.9cbs.com/read-67329.html

New Post(0)