Detailed explanation of C language custom types

1. Structure

Structure type declaration

A structure is a collection of values called member variables. Each member of the structure can be a different type of variable.

//Structure declaration describing a student
struct stu
{
    char name[20];
    int age;
    char sex[5];
    char id[20];
};

Special declaration
1. Anonymous structure type``

struct
{
    int a;
    char b;
};
struct
{
    int a;
    char b;
    float c;
}x;
struct
{
    int a;
    char b;
    float c;
}a[20], * p;
  
//p=&x;   This code is illegal because the compiler will treat the above two declarations as two completely different types
//So it's illegal

Self reference of structure

Bad self reference

struct Node
{
    int data;
    struct Node next;
};
//Is it feasible? illegal
//If so, what is the sizeof(struct Node)? beyond computation

Correct self reference method

struct Node
{
 int data;
 struct Node* next;
};
typedef struct Node
{
 int data;
 struct Node* next;
}Node;

Definition and initialization of structure variables

struct Point
{
    int x;
    int y;
}p1; //Define the variable p1 while declaring the type
struct Point p2; //Define structure variable p2
//Initialization: define variables and assign initial values at the same time.
struct Point p3 = { x, y };
struct Stu        //Type declaration
{
    char name[15];//name
    int age;      //Age
};
struct Stu s = { "zhangsan", 20 };//initialization
struct Node
{
    int data;
    struct Point p;
    struct Node* next;
}n1 = { 10, {4,5}, NULL }; //Structure nesting initialization
struct Node n2 = { 20, {5, 6}, NULL };//Structure nesting initialization

Structure memory alignment

When calculating the memory size occupied by the structure, the memory alignment of the structure should be considered

Rules for structure memory alignment

  1. The first member is at an address offset from the structure variable by 0.
  2. Other member variables should be aligned to the address of an integer multiple of a number (alignment number).
    Alignment number = the smaller value of the compiler's default alignment number and the size of the member.
    The default value in VS is 8
  3. The total size of the structure is an integer multiple of the maximum number of alignments (each member variable has an alignment number).
  4. If a structure is nested, the nested structure is aligned to an integer multiple of its maximum alignment number, and the overall size of the structure is an integer multiple of all the maximum alignment numbers (including the alignment number of nested structures).

Example exercise

struct S1
{
    char c1;
    int i;
    char c2;
};

int main()
{
    printf("%d\n", sizeof(struct S1));//12
    return 0;
}


Examples of nested structure types

struct S3
{
    double d;
    char c;
    int i;
};


struct S4
{
    char c1;
    struct S3 s3;
    double d;
};
int main()
{
    printf("%d\n", sizeof(struct S4)); //32
    return 0;
}


Why is there memory alignment?
Most references say this:

  1. Platform reason (migration reason):
    Not all hardware platforms can access any data on any address; Some hardware platforms can only get certain types of data at certain addresses, otherwise hardware exceptions will be thrown.

  2. Performance reasons:
    Data structures (especially stacks) should be aligned on natural boundaries as much as possible.
    The reason is that in order to access misaligned memory, the processor needs to make two memory accesses; Aligned memory access requires only one access.

on the whole:
The memory alignment of structures is a method of trading space for time

When designing the structure, how can we not only meet the alignment, but also save space?
Let the members with small space gather together as much as possible

struct S2
{
 char c1;
 char c2;
 int i;
};

Pre instruction for modifying the default alignment number #pragma

#pragma pack(1) / / set the default alignment number to 1
struct S2
{
    char c1;
    int i;
    char c2;
};
#pragma pack() / / unset the default alignment number and restore it to the default
int main()
{
    //What is the output?
    printf("%d\n", sizeof(struct S2)); //6
}

Structural transmission parameters

Two ways of structure parameter transmission
1. Transmission structure
2. Transfer structure variable address

struct S
{
    int data[1000];
    int num;
};
struct S s = { {1,2,3,4}, 1000 };
//Structural transmission parameters
void print1(struct S s)
{
    printf("%d\n", s.num);
}
//Structure address transmission parameter
void print2(struct S* ps)
{
    printf("%d\n", ps->num);
}
int main()
{
    print1(s);  //Transmission structure
    print2(&s); //Transmission address
    return 0;
}

The above print1 and print2 functions can access the structure, but print2 is better
reason:
When parameters need to be passed on stack, system will have time cost.

If the structure is too large when passing a structure object, the system overhead of parameter stack pressing is relatively large, which will lead to performance degradation.

Conclusion:
When a structure passes parameters, the address of the structure is passed

Structure implementation bit segment

1. The member of the bit segment must be int unsigned int signed int or char (belonging to the shaping family)
2. There is a colon and a number after the member name of the ` ` bit field.

struct A
{
 int _a:2;
 int _b:5;
 int _c:10;
 int _d:30;
};

A is a bit segment type

struct S
{
 char a:3;
 char b:4;
 char c:5;
 char d:4;
};

S is a bit segment type
Note: the number after the colon refers to the space allocated for the variable, in bit
For example:
In S, a space of 3 bits is allocated for a
3. The space of bit segment is opened up in the way of 4 bytes (int) or 1 byte (char) as required.
4. Bit segments involve many uncertain factors. Bit segments are not cross platform. Pay attention to portable programs and avoid using bit segments.

Space development:

Cross platform problem of bit segment

  1. It is uncertain whether the int bit field is treated as a signed number or an unsigned number.
  2. The number of the largest bits in the bit segment cannot be determined. (the 16 bit machine is 16 at most, and the 32-bit machine is 32 at most, which is written as 27. There will be problems on the 16 bit machine.
  3. Whether the members in the bit segment are allocated from left to right or from right to left in memory has not been defined.
  4. When a structure contains two bit segments, and the member of the second bit segment is too large to accommodate the remaining bits of the first bit segment, it is uncertain whether to discard the remaining bits or use them.

Conclusion:
Compared with the structure, bit segment can achieve the same effect, but it can save space, but there are cross platform problems

2. Enumeration

Enumeration, as the name suggests, is one by one
Give examples of possible values one by one

Definition of enumeration type

enum Day//week
{
 Mon,
 Tues,
 Wed,
 Thur,
 Fri,
 Sat,
 Sun
};
enum Sex//Gender
{
 MALE,
 FEMALE,
 SECRET
};
enum Color//colour
{
 RED,
 GREEN,
 BLUE
};

enum Day, enum Sex and enum Color defined above are enumeration types.
The content in {} is the possible value of enumeration type, which is also called enumeration constant.
These possible values have values. By default, they start from 0 and increase by 1 at a time. Of course, initial values can also be assigned when defining.
For example:

enum Color//colour
{
 RED=1,
 GREEN=2,
 BLUE=4
};

Advantages of enumeration

We can use #define to define constants. Why do we have to use enumeration?
Advantages of enumeration:

  1. Increase the readability and maintainability of the code
  2. Compared with #define defined identifiers, enumeration has type checking, which is more rigorous.
  3. Prevents naming contamination (encapsulation)
  4. Easy to debug
  5. Easy to use, you can define multiple constants at a time

Use of enumerations

enum Color//colour
{
 RED=1,
 GREEN=2,
 BLUE=4
};
enum Color clr = GREEN;//You can only assign values to enumeration variables with enumeration constants, so that there will be no type difference.

3. United Nations

Consortium is also a special user-defined type. The variables defined by this type also contain a series of members, which are characterized by the fact that these members share the same space.
For example:

Definition of union type

//Declaration of union type
union Un
{
 char c;
 int i;
};
//Definition of joint variables
union Un un;
//Calculate the size of the joint variable
printf("%d\n", sizeof(un));//4

Characteristics of joint

The members of the union share a memory space, so that the size of the union variable is at least the size of the largest member.

union Un
{
    int i;
    char c;
};


int main()
{
    union Un un;
    // Is the result of the following output the same?
    printf("%d\n", &(un.i));
    printf("%d\n", &(un.c));
    //What are the output results below?
    un.i = 0x11223344;
    un.c = 0x55;
    printf("%x\n", un.i);
    return 0;
}

Interview questions:
Calculate the storage size of the current computer
A method of judging by association

int main()
{
    union Un
    {
        char c;
        int i;
    };
    union Un un;
    un.i = 1;
    if (un.c == 1)
    {
        printf("Small end storage\n");
    }
    else
    {
        printf("Big end storage\n");
    }  
}

2. Using pointer

int nu()
{
    int a = 1;
    return *(char*)&a;
 }

int main()
{
    int ret = nu();
    if (ret == 1)
        printf("Small end storage\n");
    else
        printf("Big end storage\n");
}

Calculation of joint size

The size of the union is at least the size of the largest member.
When the maximum member size is not an integer multiple of the maximum alignment number, it should be aligned to an integer multiple of the maximum alignment number.

union Un1
{
    char c[5];
    int i;
};
union Un2
{
    short c[7];
    int i;
};

int main()
{
    printf("%d\n", sizeof(union Un1)); //8
    printf("%d\n", sizeof(union Un2));//16
    return 0;
}

Keywords: C Back-end

Added by tensionx on Fri, 04 Feb 2022 06:15:16 +0200