C language comprehension - data type

I. Overview

The programming language provides a basis for abstracting the physical world, and provides a name called a data type for describing the physical world. This data type is something that we humans can recognize, such as numbers, letters, characters, and the like.

C language also provides the term data type, just like the monkey in the picture below, if we use C language to describe the monkey in the picture, we can use the string data type in C language to describe :

char * imageDescription = "两只猴子,一个大猴子,一个小猴子";

insert image description here
The following is my understanding and use of data types in C language.

2. Basic data type

1. Integer

The integer type identifiers in C language are: int , long , long long , short , 0, -1, -23, 4235, etc., that is, integers without decimals. The most commonly used is int. long, long long is an integer suitable for large scenes . Compared with integers, the range of stored values ​​is relatively large, and the attributes are basically the same. I will use int as an example to represent integers. short is just a relatively small index range value when used. There will be a special table to summarize the memory model of these variables later.

Integers in the C language are very useful, because the internal calculations use binary to represent data, and the data inside are essentially integers, and floating-point numbers are also described by binary integers. Integers have many properties that are very useful, such as the result of integer division is also an integer and so on. The biggest use of integers outside of calculations is indexing. Integers are used in scenarios such as arrays, loops, judgments, and address indexes.

1. Calculate

It is also very simple to declare an int variable, just the name of the int variable; if it is not initialized, it will give a random value by default, so be sure to remember to initialize it. Because when it is like a loop, you always have to index from a valid start index. If the value is not set, this will cause problems, and a segment fault will occur.

A very useful calculation of integers in C language is division, and the remainder operation can only be integers.

Just like below, the division will throw away the fractional part of the divided number, and only keep the integer part

// 声明变量并初始化,初始化就使用 = 
int i = 0;

i = 1 / 2;	//i = 0

The remainder operation is also very simple

int i = 11;

i = i / 2;	//i = 0

Corresponding to the most classic is a hundred

#include <stdio.h>

int main()
{
    
    
    int numA, numB, numC, numD;
    printf("请输入一个三位数: ");
    scanf("%d", &numA);
    numA = (int)numA;
    numD = numA % 10;
    numC = (numA / 10) % 10;
    numB = numA / 100;
    printf("这个三位数的个十百分别为:%d %d %d",numD, numC, numB);
    return 0;
}

2. Index

The essence of an array is actually a data table. A one-dimensional array is a single-row table, and a two-dimensional array is a multi-row table. Integers can actually be used as a powerful tool to represent positions when indexing.

Just like the following two-dimensional data table uses row-column to determine the position, it is obviously impossible to use floating point numbers here.

table[row index][column index] to determine the value of a location
insert image description here

int martx[3][3] = {
    
    {
    
    0, 1, 2}, {
    
    4, 5, 6}, {
    
    7, 8, 9}};

For the above martx array, we need to get the data of the second row and the first column by using martx[1][0] .

The most flexible is the change to this index .

2. Floating point numbers

Floating-point numbers are actually decimals, and by the way, the writing method of scientific notation is also a floating-point number type.

The types of floating-point numbers in C language are float and double . In fact, it is a difference between low precision and high precision. Generally, double is used more.

In fact, I don’t think too much about the use of this, but one thing to consider is that when it is operated with other data, it will make the data type rely on floating-point numbers.

Just like the result of 7+7.32 is floating point
but the result of 7+7 is integer

3. Characters

4. string

5. pointer

A pointer is a data type, a type that stores the addresses of other variables. The pointer is a big content, if you are interested, you can take a look at my notes

Getting Started with Pointers Basic
C Dynamic Memory Management
Pointers and Function
Pointers and Array
Pointers and Strings

3. Special data types

1. Enumeration

enum

2. Community

uion

2. struct structure

The struct structure C language provides us with an open and powerful tool for defining our own data types. We can use struct to describe a data structure. In this structure, the data types mentioned above are used, and of course they are also included in The structure is stored again in the structure.

For example: we use a structure to describe the data of a circle located on the screen.

This circle has a radius, the circle has the coordinate position relative to the upper left corner of the screen, the circle also has data such as the line width of the outer circle, the color of the outer line, and the fill color of the inner circle.

1. Define the structure

struct structure name {internal type};

When using it, just use the struct structure name as a custom type, just like int.

Then to define such a circle can be written as follows

// 颜色结构体
struct color{
    
    
    short red;
    short green;
    short blue;
};

// 位置
struct point{
    
    
	int x;
	int y;
}

// circule
struct circule{
    
    
	int Radius;
	struct point Point;
	struct color OuterColor;
	struct color InnerColor;
}

But this way of writing may be a bit long, then we can use typedef to name this structure the same as our more readable variable type name.

typedef 类型 自己想要的类型名

You can rewrite the above code

struct color{
    
    
    short red;
    short green;
    short blue;
};

//定义别名
typedef struct color ST_Color;

// 位置
struct point{
    
    
	int x;
	int y;
};

typedef struct point ST_Point;

// circule
struct circule{
    
    
	int Radius;
	ST_Point Point;
	ST_Color OuterColor;
	ST_Color InnerColor;
};

typedef struct circule ST_Circule;

Of course, we can also directly use typedef to simplify the definition, and give it an alias when it is a structure

typedef struct color{
    
    
    short red;
    short green;
    short blue;
} ST_Color;

2. Use the structure

The use of the structure is also very simple, just like ordinary types, just use the '.' symbol to access the internal members of the structure

Below I will declare a circular structure

// 声明结构体
ST_Circule m_circlue;
ST_Circule *p_circle = NULL;

// 初始化结构体
m_circlue.Radius = 10;
m_circlue.Point = {
    
    0,0};	//这种是是用列表初始化
m_circlue.InnerColor = {
    
    12,23,34};

m_circlue.OuterColor.blue = 12;	//这种是每个单独的去初试化
m_circlue.OuterColor.red = 23;
m_circlue.OuterColor.green = 34;

//在使用结构体指针的时候,为了区分是指针所有还是用的变量名索引,在访问结构体成员变量的时候会用 -> 来区分
p_circle = &m_circlue;
printf("m_circlue-Radius: %d", p_circle->Radius);

3. Memory layout
The memory size of a structure is theoretically the sum of the memory sizes of all its internal members. And the memory arrangement order of the members must be the definition order.

insert image description here

Theoretically speaking, each member of the structure is stored continuously in memory, which is very similar to an array. However, the total size of the memory occupied by the structure is not necessarily equal to the sum of the memory size occupied by all member variables. In the specific implementation of the compiler, in order to improve the efficiency of memory addressing, gaps may exist between various members.

Just like the theoretical size of ST_Circule is 24 bytes. It is continuous.

In the structure, the memory is not completely contiguous, but it is actually memory-aligned.

Default Byte Alignment Policy

First of all, a concept of natural alignment (naturally aligned) is introduced, which means that the starting address of the data is a multiple of the size of the data type. The alignment of the structure means that each data member in it is naturally aligned . To achieve this effect, it may be necessary to perform necessary byte padding between the members. For example, look at struct:

struct Struct {
    
    
  char c1; // 1B
  uint64_t n1; // 8B
};

By default, 7 bytes need to be filled after c1 to ensure that n1 is naturally aligned. At this time sizeof(DemoStruct)==16

The general alignment principles of C/C++ struct are as follows:
Order preservation:
Each member is guaranteed to be naturally aligned on the basis of order preservation. If the address immediately following the previous member does not meet the alignment requirements, padding is added.
Padding may also be added after the last member, so as to ensure that when the struct array is created, each struct in the array is still aligned.
When the structure is nested, recursively align according to the largest member in the structure. (Note that it is not the largest structure, but the member with the largest total structure )

pragma pack(1) erase padding

We can use #pragma pack(1) to force the struct not to add padding, such as the following struct:

#pragma pack(1)
struct DemoPackStruct {
    
    
  char c1; // 1B
  uint64_t n1; // 8B
};

Since the forced alignment is changed to 1 byte, there is no need for padding in the above structure. At this time sizeof(DemoPackStruct)==9.

The main purpose of doing this is to save memory at the cost of losing memory access efficiency. There may be another function to facilitate the network transmission of data structures, such as directly avoiding the serialization process and sending the entire data structure over the network, but this is not safe, because there are endian problems between different machines (big endian/ little endianness).

Of course, you can also specify a larger pack value to force the struct to be aligned with a larger byte, such as the following data structure sizeof(DemoPack2Struct)==10:

#pragma pack(2)
struct DemoPack2Struct {
    
    
  char c1; // 1B
  uint64_t n1; // 8B
};

When using pack, you need to pay attention to the following points:

The value of pack(n) must be an exponent of 2, such as n can be 1, 2, 4, etc.

pack can only be used to reduce padding of sturct, not to increase padding. For example, the largest member in a struct is 8 bytes, then pack(16) has no effect.

#pragma pack() affects all struct declarations after this statement, and the previous default pack can be saved and restored by pack(push), pack(pop)

Fourth, the data type modifier

1. const

2. unsigned、signed

Guess you like

Origin blog.csdn.net/qq_43680827/article/details/130666562