Sizeof, ultimate;

zhaozj2021-02-16  81

0. Beforewards

SizeOf, a guy who is unstoppable, caught in the waist, Xiaob Shrob, I didn't have a relaxation, and I made it a great idea of ​​"hard me, happiness tens of thousands of people", I decided to summarize it in detail.

But when I summed it, I found that this problem can be easier and complicated, so there is not suitable for beginners, and even there is no need to master. But if you want to "know it, better", then this article can help you.

The rookie has not been in-depth for C , including mistakes, welcome to throw the bricks.

Define

Why is SIZEOF? SizeOf is an operator in C / C is also, simply saying that the role is to return an object or type of memory byte number of memory bytes.

The explanation on the MSDN is:

The Sizeof Keyword Gives The Amount of Storage, In Bytes, Associated with a variable or a type (include).

This Keyword Returns a value of type size_t.

Its return value is SIZE_T, defined in the header file stddef.h. This is a value dependent on the compilation system, which is generally defined as:

Typedef

unsigned

Int size_t;

The main compiler of the world, but as a norm, they will guarantee the sizeof value of char, souded char and unsigned char, after all, Char is the minimum data type we have programmed.

2. Syntax

SizeOf has three grammar forms as follows:

1) SIZEOF (Object); // sizeof (object);

2) SIZEOF (Type_name); // sizeof (Type);

3) sizeof object; // sizeof object;

and so,

INT I;

SizeOf (i);

// ok

SizeOf I;

// ok

Sizeof

Int);

// ok

Sizeof

Int;

// Error

Since writing method 3 can be used to write method 1, in order to unify the form and reduce the burden of our brain, the third way of writing, forget it!

In fact, the size of the SIZEOF calculation object is also converted to the type of object type, that is, the same type of different objects have a SIZEOF value. Here, the object can further extend to the expression, ie, SizeOf can be evaluated to an expression, the compiler determines the size according to the final result type of the expression, generally does not calculate the expression. Such as:

SizeOf (2);

// 2 type is int, so equivalent to Sizeof (int);

SIZEOF (2 3.14);

// 3.14 Type of Double, 2 will also be upgraded into a Double type, so equivalent to Sizeof (Double);

SIZEOF can also call a function call, and the result is the size of the function returns the type, the function will not be called, let's take a complete example:

Char foo ()

{

PRINTF

"Foo () HAS been Called./N");

Return 'a';

}

int main ()

{

SIZE_T SZ =

SizeOf (Foo ());

// foo () return value type is char, so SZ = SizeOf (char), foo () will not be called Printf (

"SIZEOF (Foo ()) =% D / N", SZ);

}

C99 Standards, functions, unable to determine the type of expression and bit-field member cannot be calculated, namely, the following writes are wrong:

SizeOf (foo);

// Error

Void foo2 () {}

SizeOf (Foo2 ());

// Error

Struct S

{

unsigned

INT F1: 1;

unsigned

INT F2: 5;

unsigned

INT F3: 12;

}

SIZEOF (S.f1);

// Error

3. Sterregation of SizeOf

The calculation of SIZEOF occurs at the compilation time, so it can be used as a constant expression, such as:

Char ary [

Sizeof

Int) * 10];

// ok

The latest C99 standard specifies that SizeOf can also be calculated at runtime, as follows: The following can be performed correctly in DEV-C :

Int n;

N = 10;

// n Dynamic assignment

CHAR ARY [N];

// c99 also supports dynamic definitions of arrays

PRINTF

"% d / n",

SizeOf (ary);

// ok. Output 10

However, in the compiler that does not fully implement the C99 standard, the above code is not compiled in VC6. So we'd better think SIZEOF is executed in the compile period, which will not cause errors to make the program's portability.

4. SIZEOF for basic data types

The basic data type here refers to the simple built-in data type of short, int, long, float, double, because they are related to the system, so the value in different systems may be different, this must be caused by our attention, try to Don't give trouble in this area.

In general, in the 32-bit compilation environment, the value of SIZEOF (int) is 4.

5. Sizeof in pointer variable

You should know that the pointer is a very important concept that records the address of another object. Since it is to store the address, it is of course equal to the width of the internal address bus of the computer. So in the 32-bit computer, the return value of a pointer variable must be 4 (note that the result is in bytes), which can be expected that the sizeOf result of the pointer variable in the future 64-bit system is 8.

Char * pc =

"ABC";

INT * PI;

String * ps;

Char ** PPC = & PC;

Void (* pf) ();

// Function pointer

SizeOf (PC);

/ / The result is 4

SizeOf (PI);

/ / The result is 4

SizeOf (PS);

/ / The result is 4

SIZEOF (PPC);

/ / The result is 4

SizeOf (PF);

/ / The result is 4

The sizeof value of the pointer variable does not have any relationship with the object referred to by the pointer. It is because all the pointer variables are equal to the memory size, so the MFC message processing function uses two parameters WPARAM, LPARAM can deliver a variety of complex message structures ( Use a pointer to the structure).

6. Array Sizeof

The sizeof value of the array is equal to the number of memory bytes occupied by the array, such as:

Char A1 [] =

"ABC";

Int A2 [3];

SizeOf (A1);

/ / The result is 4, and there is a NULL terminator at the end of the string.

SizeOf (A2);

/ / The result is 3 * 4 = 12 (depending on int)

Some friends have just started the number as a number of group elements, now you should know that this is not right, then how should you ask the number of array elements? Easy, usually there are two ways:

INT C1 =

SizeOf (A1) /

Sizeof

Char);

// Total length / single element length

INT C2 =

SizeOf (A1) /

SizeOf (A1 [0]);

// Total length / length of the first element

Write here, ask, what is the C3 and C4 value below?

Void foo3

Char A3 [3])

{

INT C3 =

SIZEOF (A3);

// c3 ==?

}

Void foo4

Char a4 [])

{

INT C4 =

SIZEOF (A4);

// c4 ==?

}

Maybe when you try to answer the value of C4, you have realized that C3 has an error, yes, C3! = 3. Here the function parameter A3 is no longer an array type, but it turns into a pointer, which is equivalent to char * a3, why? If you think about it, it is not difficult to understand. When we call the function foo1, will the program allocated an array of 3 in the stack? will not! The array is "in-service", the caller only needs to pass the address of the arguments, so A3 is naturally a pointer type (char *), and the value of C3 is 4.

7. SIZEOF structure

This is a problem that beginners asked the most, so there is a need to book a pen ink here. Let us first look at a structure:

Struct S1

{

Char C;

INT I;

}

How much is SIZEOF (S1)? Smart, you start thinking, Char accounts for 1 byte, Int accounts for 4 bytes, then add up should be 5. Is that right? Have you tried it on your machine? Maybe you are right, but it is very likely that you are wrong! The result of the default setting is 8 in VC6.

Why? Why am I always the one who's hurt?

Please don't be frustrated, let's take a good idea of ​​SIZEOF - the result of the SizeOf is equal to the number of internal memory byte, ok, let's take a look at the memory allocation of S1:

S1 S1 = {'a', 0xffffffff};

After defining the above variables, add a breakpoint, run the program, observe the memory where S1 is located, what did you find?

Taking my VC6.0 as an example, the address of S1 is 0x0012FF78, and its data content is as follows:

0012FF78: 61 CC CC CC FF FF FF

What did you find? How to mix 3 bytes of CC in the middle? Take a look at the description of the MSDN:

.

It turns out that this is the legendary byte! An important topic appeared.

Why do you need a byte alignment? The principle of computer composition teaches us to help speed up the computer's number of speeds, otherwise it will have a multi-flowering command cycle. To this end, the compiler will process the structure by default (this is also the data variable in other parts, so that the basic data type (Short, SHORT, etc.) capable of being able to be completely removed, so that the width is 4 The basic data type (INT, etc.) are located on an address that can be 4 completely, and push it. Thus, the middle of the two numbers may need to add a padding byte, so the sizeof value of the entire structure increases. Let us exchange the position of CHAR and int S1:

Struct S2

{

INT I;

Char C;

}

See how much SIZEOF (S2) is, how is it still 8? Take a look at memory, there is still three filling bytes behind the member c, which is why? Don't worry, summarize the law.

The detail of the byte alignment and the compiler implementation, but in general, meet three guidelines:

1) The first address of the structural variable can be removed by the size of its widest basic type member;

2) The offset of each member of the structure relative to the structure of the structural body is an integer multiple of the member size. If a compiler is needed, the compiler will be plus a fill byte (INTERNAL Adding)

3) The total size of the structure is an integer multiple of the larger basic type member size of the structure. If a compiler is required to add a fill byte after the last member.

For the above guidelines, there is a need to explain:

1) The front is not the address of the structure of the structure is an integer multiple of its size. How can I say the offset? Because there is a 1st point, we can only consider the offset of members, so thinking about it. Think about why. The offset of a member of a member relative to the structure of the structure can be obtained by macro OFFSTOF (), which is also defined in STDDEF.H, as follows:

#define offsetof (s, m) (SIZE_T) & ((S *) 0) -> M)

For example, if you want to get the offset of C in S2, the method is

SIZE_T POS = Offsetof (S2, C);

// POS is equal to 4

2) Basic types refer to built-in data types like char, short, int, float, double mentioned above, and "Data Width" herein refers to its size of its SIZEOF. Since members of the structure can be a composite type, such as another structure, it should include sub-members of the composite type member when looking for the widest basic type member, rather than regarding composite members as a whole. However, when determining the offset position of the composite type member, the composite type is treated as an overall.

It is a bit embarrassing here, thinking is a little scratch, or let us look at the example (the specific value is still vc6 as an example, will no longer explain):

Struct S3

{

CHAR C1;

S1 S;

Char C2

}

The type of the widest basic member of S1 is int, S3 is considering the widest basic type member, so the widest basic type of S3 is int, so that the variable defined by S3 is stored. The first address of the space needs to be 4, and the value of the entire SIZEOF (S3) should also be divided by 4.

Is the offset of C1 of 0 and S? At this time, S is a whole, which also satisfies the three criters in front of the structural variable, so it is 8, the offset is 4, and the C1 and S need three filling bytes, and C2 and S are It is not required, so the offset of C2 is 12, and the size of C2 is 13, 13 is not 4, which is still added to three filling bytes at the end. Finally, the value of SIZEOF (S3) is 16. With the above description, we can get a formula:

The size of the structure is equal to the offset of the last member plus the size of its size plus the number of padded bytes, namely:

SIZEOF (STRUCT) = Offsetof (Last Item) SizeOf (Trailing Padding)

Here, friends should have a new understanding of SizeOf, but don't be too early, there is an important parameter that affects SizeOf has not been mentioned, which is the Pack instruction of the compiler. It is used to adjust the structure alignment, and different compiler names and use methods are slightly different. VC6 can be implemented by #pragma pack, or the / zp compilation switch can also be modified. #Pragma Pack's basic usage is: #pragma pack (n), n is the number of bytes, with a value of 1, 2, 4, 8, 16, the default is 8, if this value is a SIZEOF value of the structure Small, then the offset of the member should be as accurate in this value, ie, the offset of structural members should take the minimum value, the formula is as follows:

OFFSTOF (item) = min (n, sizeof (item))

Look at the example:

#pragma pack

Push)

// Set the current Pack to set the stack save

#pragma pack (2)

/ / Must be used before the structural definition

Struct S1

{

Char C;

INT I;

}

Struct S3

{

CHAR C1;

S1 S;

Char C2

}

#pragma pack

POP)

/ / Restore previous pack settings

When calculating SIZEOF (S1), the value of MIN (2, SIZEOF (I)) is 2, so the offset of I is 2, and the sizeOf (I) is equal to 6, and can be divided by 2, so the size of the entire S1 is 6.

Similarly, for the offset of SizeOf (S3), S is 2, the offset of C2 is 8, plus SIZEOF (C2) equal to 9, can not be removed, add a padding byte, SIZEOF (S3) is equal to 10.

Now, friends can easily take a breath, :)

Another point to note that the size of the "empty structure" (excluding data member) is not 0, but 1. Imagine a variable of "not occupying the space" to take the address, how is the two different "empty structural" variables distinguished? As a result, the "empty structure" variable has to be stored so that the compiler can only be occupied by the space allocated one byte. as follows:

Struct S5 {};

SIZEOF (S5);

/ / The result is 1

8. SIZEOF in the domain structure

As mentioned earlier, the bitmaster cannot be separated by a SIZEOF value alone. We will discuss the SizeOf of the structure containing the domain, just taking into account its specialty, it is specifically columnized.

C99 specifies that int, unsigned int and bool can be used as a bit domain type, but the compiler extends almost all, allowing other types of types. The main purpose of the use of the bit is to compress storage, and its approximate rules are:

1) If the type of neighbor domain field is the same, its bit width is smaller than the type of SIZEOF size, the following fields are stored next to the previous field until they cannot be accommodated;

2) If the adjacent domain field is the same, its bitwidth and larger than the type of SIZEOF size, the later field will start from the new memory cell, its offset is an integer multiple of its type size;

3) If the type of the adjacent bit field field is different, the specific implementation of each compiler is different, and VC6 takes no compression, DEV-C takes a compression method;

4) If you wear a non-bit field field between the bit domain field, it is not compressed.

5) The total size of the entire structure is an integer multiple of the widest basic type member size.

Or let's take a look at the example.

Example 1

Struct BF1

{

CHAR F1: 3;

CHAR F2: 4;

CHAR F3: 5;

}

Its memory layout is:

| F1 | F2 | | F3 | |

---------------------------------

| | | | | | | | | | | | | | | | |

---------------------------------

0 3 7 8 13 16 (Byte)

The bit domain type is CHAR, and the first byte can only accommodate F1 and F2, so F2 is compressed into the first byte, and F3 can only start from the next byte. Therefore, the result of SIZEOF (BF1) is 2. Example 2:

Struct BF2

{

CHAR F1: 3;

SHORT F2: 4;

CHAR F3: 5;

}

Since adjacent bit domain types are different, SizeOf is 6 in VC6, 2 in DEV-C . Example 3:

Struct BF3

{

CHAR F1: 3;

Char F2;

CHAR F3: 5;

}

The non-bit field field is inserted therein, and does not generate compression, and the size obtained in VC6 and DEV-C is 3.

9. Sizeof of the consortium

The structural body is sequentially in memory organization, and the consortium is overlapping, each member shares a memory, so the SIZEOF of the entire consort is also the maximum of each member SIZEOF. Members of the structure can also be a composite type, here, composite type members are considered as a whole.

Therefore, in the following example, the sizeof value of u is equal to SIZEOF (S).

Union u

{

INT I;

Char C;

S1 S;

}

(For the insider of Sizeof in C , please pay attention to the second part of this article)

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

New Post(0)