learn_C_deep_9 (understand the meaning of return from the perspective of assembly, various application scenarios of const)

return keyword

        I don’t know if all of us have a doubt: we download a large-scale game software ( Glory of the King ), it takes several hours to download, but once we lose the game in a row, when we want to delete this software, it only takes a dozen Second, why is this? Today we will take this doubt and solve this problem together.

In the computer, does freeing up space really mean clearing all our data?

        In a computer, freeing up space does not necessarily mean clearing all the data in it. To free up space, that is, to delete files, the computer will not immediately clear or delete the contents of the files. In fact, the computer operating system usually just marks the disk space corresponding to these files as reusable , and then overwrites it when new data needs to be stored. Therefore, even if a file is deleted, its contents may still exist on the hard drive or other storage device and can be recovered as long as it has not been overwritten.

         Summary: When you delete a file, the computer only needs to simply mark the storage space where the file is located as available without actual data transfer, so the speed of deleting data is faster. 

Let's look at a piece of code

#include <stdio.h>
char* show()
{
	char str[] = "hello world";
	return str;
}
int main()
{
	char* s = show();
	printf("%s\n", s);
	return 0;
}

        This code mainly involves two issues: the life cycle of local variables and memory safety.

First, let's look at the lifetime of local variables . In the function show(), the variable str is a local variable defined in the function body. The life cycle of local variables is only in the function body, and will be destroyed once the function is executed. Therefore, after the return str; statement is executed, the memory space occupied by the variable str is released .

Next, we look at the issue of memory safety . In the show() function, we returned the address of the variable str as the return value to the caller. Since the memory space where the variable str is located has been released , the memory space pointed to by the returned pointer s is no longer guaranteed to be safe. In the main() function, we call the printf() function to output the string in the memory space pointed to by s. Because this memory space may have been used by other programs or systems, it will cause unknown errors. This is also often referred to as the "wild pointer" problem.

 Let's take a closer look at the release process

Summary: The return statement in this code cannot return a " pointer  " pointing to "stack memory ", because this memory is automatically destroyed at the end of the function body.

Is it strange here? Didn't we just say that the stack frame will be released after the function is called, and the data x inside should be overwritten after the printf function, but why can we print it here? - Here we will introduce the return keyword

        The return statement is a keyword in C language that ends the execution of the current function and returns a value or no value. In most cases, the return statement is used to return the result of a function execution to the caller.

        The return statement has many different uses and grammatical structures, the most common of which are:

```

c return expression;

```

Among them, expression can be a constant, variable, expression or return value of other function calls, and this value will become the return value of the function and be returned to the caller.

        Our above code returns the value of x. The return keyword in the function stack frame saves the value of x in the register, and brings the value of x back to y in the main function through the register. If it is the address of x, it will also be returned, but the value in it cannot be printed. The compiler will issue a warning.

const keyword

        const is a keyword in the C language. Its function is to modify the variable, indicating that the value of the variable cannot be directly modified. This means that once a variable declared with the const keyword is assigned a value during program execution, it cannot be modified. The const keyword can be used to modify variables of basic data types, structures, pointers, and other types.

        Using the const keyword has the following benefits:

1. The readability of the program is better. Using the const keyword can clearly tell other programmers that the variable is a constant and should not be modified.

2. The program is safer. Using the const keyword can avoid accidentally modifying a variable that should be a constant in the program, which improves the robustness of the program.

3. The compiler can use the const keyword to optimize the program. For example, in some cases, the compiler can directly embed the constant into the code, which improves the execution efficiency of the program.

const modified read-only variables - - - cannot be modified directly!

 Cannot be modified directly, but can be modified indirectly - by address

 Conclusion: The variable modified by const is not really a constant that cannot be modified.

Can const-decorated variables be part of an array definition?

const int n = 100;

int arr[n];

        Here you can see another article I wrote, which introduces it.

Summary: An error is reported directly under vs2013 (standard C), but under gcc (GNU extension), it is ok. But we are all in line with the standard, it cannot be done.

const can only be initialized directly when it is defined, and cannot be assigned twice. Why?

        The role of the const keyword is to tell the compiler that the variable is a constant and should not be modified. Therefore, once a variable declared with the const keyword is assigned a value during program execution, it cannot be modified.

        In order for the compiler to achieve this goal, the const keyword will perform some optimizations on the variable during compilation, so that the value of the variable cannot be modified during program execution. If the variable is allowed to be assigned a second time during the running of the program, the compiler cannot guarantee that the value of the variable will not be modified, which is contrary to the meaning of the const keyword.

        Therefore, const can only be initialized directly when it is defined, and the reason why it cannot be assigned twice is to ensure the robustness and security of the program. If you really need to dynamically modify the value of a variable during program execution, you should use ordinary variables instead of const-modified variables.

const modified pointer

First introduce the concept of lvalue and rvalue

        In computer programming, lvalue and rvalue are two types of expressions.

        The lvalue represents the object to be assigned, which can appear on the left side of "=", or in any operand of the expression. Lvalues ​​can appear in multiple operations and can be changed.

        An rvalue represents a value that can be assigned to an lvalue, and an rvalue can appear in any operand of an expression, but cannot be changed. An rvalue is usually a temporary value that is used to evaluate an expression and whose value is discarded when the expression has finished executing.

There are also lvalues ​​and rvalues ​​for pointer variables.

        In the C language, a pointer is a special variable that stores a memory address and can be used to access the data stored at that address. When defining a pointer variable, we can use the const keyword to determine whether the pointer and the data pointed to by the pointer can be modified.

        1. const int* p;

        The const here acts on the data pointed to by the pointer, indicating that the data pointed to by p cannot be modified. In other words, we can read this constant data through the p pointer, but we cannot modify this data through the p pointer. For example: p itself can be modified (such as p++), but the int type variable pointed to by p cannot be modified (such as *p=10 is illegal).

        2. int const* p;

        This definition is equivalent to the above definition, the position of the const keyword is different but the meaning is the same.

        3. int* const p;

        The const here acts on the pointer itself, indicating that the p pointer itself cannot be modified. In other words, we cannot make it point to other addresses by changing the value of the p pointer, but we can modify the data stored in this address through the p pointer. For example: p itself cannot be modified (such as p++ is illegal), but the int type variable pointed to by p can be modified (such as *p=10 is legal).

        4. const int* const p;

        There are two const keywords in this definition, one for the pointer itself and one for the data pointed to by the pointer. Indicates that the p pointer itself and the data pointed to by p are unmodifiable, that is to say, the p pointer can only point to a certain address, and the data stored in this address cannot be modified. For example: p itself cannot be modified (such as p++ is illegal), and the int type variable pointed to by p is also non-modifiable (such as *p=10 is illegal).

        const int* p1 = &a;

        int* q1 = p1;

Here, the pointer p1 of the const int* type is assigned to the pointer q1 of the int* type, which is not safe. Because p1 points to an unmodifiable constant int type variable, if the variable pointed to by p1 is modified through the q1 pointer, undefined behavior will occur. The correct way is to cast the pointer type to a non-const type, namely: int* q1 = (int*)p1;

        int* const p2 = &b;

        int* q2 = p2;

Here, it is safe to assign the pointer p2 of type int* const to the pointer q2 of type int*. Because p2 points to a modifiable int type variable, and p2 itself is not modifiable. Also, it is safe to assign a pointer of const type to a pointer of non-const type. So there is no problem with this code and no changes are required.

Parameters of const modified functions

         In the C language, we can also use the const keyword to modify the parameters of the function, which means that the function will not modify the value of the modified parameter. The parameters in a function can be divided into formal parameters and actual parameters. The formal parameters are the variables defined in the function, and the actual parameters are the values ​​passed to the function when the function is called. When the const keyword is used to modify a formal parameter, it means that the value of this formal parameter cannot be modified in the function. If the function tries to modify the parameter modified by const, the compiler will report an error.

        The following is an example of using const to decorate function parameters:

void print_array(const int* arr, int n)
{
    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

int main(void)
{
    int arr[] = { 1, 2, 3, 4, 5 };
    print_array(arr, 5);
    return 0;
}

        In this example, the first parameter of the print_array function is a const int* type, which means that the pointer points to an unmodifiable memory, and the value corresponding to this memory cannot be modified in the function. The second parameter is an ordinary int type, indicating the length of the array. Inside the function, we have used a for loop to iterate through the array and printed each element in the array using the printf function. Because we declared the first parameter as const int* type, the value pointed to by this pointer cannot be modified in the function. If the function tries to modify the value pointed to by this pointer, the compiler will report an error.

        This helps protect the values ​​in the array from accidental modification, improving program robustness.

Does the function form a temporary variable when passing parameters?

        In the C language, function parameters are passed by value or by address. When we call a function, the value of the actual parameter is copied and passed to the function, while the formal parameter defined in the function is a new variable. During this process, a temporary variable is indeed generated to store the value of the actual parameter.

Bye-Bye! ! !

Guess you like

Origin blog.csdn.net/qq_64446981/article/details/130543352