This is the 11th day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021 “@TOC

Nanny level explanation! C language user-defined type.

@TOC


preface

In our daily code, we often encounter the use of structure type, today let readers understand the use of structure type.


First, the initial structure

So before we look at structures, let’s look at the basics of structures and just say, what is a structure? A structure is a collection of values called member variables. Each member of a structure can be a variable of a different type. Here’s an example:

struct tag
{
  menber_list;  // Member list
}variable_list; // List of variables
Copy the code

For example, we use structures to describe a computer

struct computer
{
 int price;/ / price
 char name[20];/ / name
 char brand[10];/ / brand} computer;// Note the "; "in the last line. Do not throw it, or the compiler will give you an error.
Copy the code

Structure members can be scalar arrays, Pointers, or even other structures.

Example: Pandas is a numpy-based tool that was created to solve data analysis tasks.

Anonymous structure type

// Anonymous structure type
struct
{
 int a;
 char b;
 float c;
}x;
struct
{
 int a;
 char b;
 float c;
}a[20], *p;
Copy the code

In the above code, the structure has omitted the structure tag, and we are adding a line of code

P = & x;Copy the code

When we compile, we find two errors like this.So that’s not going to work.

A self-reference to a structure

Just like function recursion, structures can refer to themselves. Here’s their format.

struct Node
{
 int data;
 struct Node* next;
};
Copy the code

Structure variable definition and initialization

struct stu
{
	char name[20];
	int age;
	
};
struct stu s = { "Geralt ".100};
Copy the code

Geralt of Livia, 100 years old!

Internal alignment of the structure

The offset of the start address of each member variable relative to the start address of the structure must be a multiple of the number of bytes occupied by the type of the variable. Each member variable applies for space according to the order in which it appears in the structure and adjusts its position according to the alignment above. Empty bytes are automatically filled And to ensure that the size of the structure is a multiple of the structure’s byte boundaries (that is, the number of bytes of the type that occupies the most space in the structure), space is allocated for the last member variable and the empty bytes are automatically filled as needed. To put it simply: memory alignment of structures is the result of trading space for time, increasing efficiency and wasting a little space. Here are the rules:

  1. The first member is at an address offset 0 from the structure variable.
  2. Other member variables are to be aligned to an address that is an integer multiple of a number (the aligned number).

Alignment number = a compiler default alignment number and a smaller value of the member size. 3. The total size of the structure is an integer multiple of the maximum aligned number (one aligned number for each member variable). 4. In the case of nested structures, the nested structure is aligned to an integer multiple of its own maximum number of alignments. The overall size of the structure is an integer multiple of the maximum number of alignments (including nested structures).

The default alignment number in the VS compiler is 8.

Of course, as creators of VS Linux, we can customize alignment numbers in C.

We can modify the default alignment number using the #pragma preprocessor.

#pragma pack(4) // Change alignment number to 4

Structure parameter transfer

struct s
{
	int data[1000];
	int num;
};
struct s s ={{1.2.3.4},100 };
// Struct pass parameter
void print1(struct s s)
{
	printf("%d\n", s.num);
}
// Structure address pass parameter
void print2(struct s* ps)
{
	printf("%d\n", ps->num);
}

int main(a)
{
	print1(s);
	print2(&s);




	return 0;

Copy the code

Parameters, like function parameters, are temporary copies of arguments that need to be pushed, resulting in time and space overhead. If the structure is too large in the process of passing, the system overhead may be high, resulting in performance degradation. We might as well just pass an address and dereference it.

Second, a segment

1. The member of a bit segment must be an int, unsigned int, or signed int. 2. The member name of the bit segment is followed by a colon and a number.

Struct A {int _a:2;

int _b:5; int _c:10; int _d:30; };

Bit segment memory allocation
  1. The members of a bit segment can be of type int unsigned int signed int or char (a member of the integer family)
  2. The space of the bit segment is opened up as needed by 4 bytes (int) or 1 byte (char).
  3. Bits involve a lot of uncertainty and are not cross-platform, so applications that focus on portability should avoid using bits.
  4. Let me give you an example

struct S { char a:3; char b:4; char c:5; char d:4; }; struct S s = {0}; s.a = 10; s.b = 12; s.c = 3; s.d = 4; So how do bits open up space? One picture!

In general, bit segments are similar to structures and can save more space, but bit segments have the problem of cross-platform.

Third, the enumeration

Enumeration, as the name implies, is a list of possible values. For example, we want to describe the months of the year. We want to describe the types of computer languages. Here is an example of the following code (example) :

enum  ComputerLangue
	{
		C,
		Java,
		Python,

	};
Copy the code

Each structure has certain advantages, so what are the advantages of enumerations?

  1. Increases code readability and maintainability
  2. Enumerations are more rigorous in type checking than the identifiers defined by #define.
  3. Prevents naming contamination (encapsulation)
  4. Easy to debug
  5. Easy to use, you can define multiple constants at once

Union (common body)

The characteristic of a union is that its members share the same space, so they can also be called Commons

The code is as follows (example) : // Declaration of the union type

union Un 
{ 
 char c; 
 int i; 
};
Copy the code
// The definition of the union variable
union Un un; 
// Calculate the size of each variable
printf("%d\n".sizeof(un));
Copy the code

Three, practice

How many bytes of space does this structure take up in the VC2013 compiler?

typedef struct{
  int a;
  char b;
  short c;
  short d;
}AA_t;
Copy the code

The answer is: 12 bytes why? The structure determines the size and is generally aligned to the longest element in the member.Of the four structure members, the longest element is a, which is four bytes long. So everything else has to be aligned to four. A alone takes four bytes, B for char takes one byte, and C for short and B together take four bytes and leave one byte empty. That leaves d one byte, two bytes empty. So the total space is 4+1+2+2+3=12 bytes.

struct A
{
 int a;
 short b;
 int c;
 char d;
};
struct B
{
 int a;
 short b;
 char c;
 int d;
};
Copy the code

Sizeof (A) and sizeof(B) are () on 32-bit systems where the compilation option is 4-byte alignmentThe longest structure members are 4 bytes int, 2 bytes B, 2 bytes empty, 4 bytes C, 1 byte D, 3 bytes empty.The longest type is int, where a takes 4 bytes, b and C together take 3 bytes, with the next byte left empty, and D takes 4 bytes. So sizeof (A)sizeof (B) is 16, 12.

conclusion

We introduced C’s custom types, structs, unions, enumerations, and bits, which can help us use C more efficiently.