Array Storage and Pointer Study Notes (2) Enumeration Types, Constants and Variables

Embedded C language learning advanced series of articles

GUN C Compiler Extended Grammar Study Notes (1) GNU C Special Grammar Part Detailed
GUN C Compiler Extended Grammar Study Notes (2) Attribute Declaration
GUN C Compiler Extended Grammar Study Notes (3) Inline Functions, Built-in Functions and Available Functions Variable parameter macro
array storage and pointer study notes (1) data type and storage, data alignment, data migration, typedef



1. Enumeration type

  Enumeration (enum) is a special type of C language. When we want to define a set of fixed length or range of values ​​in the program, we can consider using enumeration type. Using enumerations can make programs more readable and look more intuitive.
insert image description here
  In the list of enumeration constant values ​​defined by enum, the default starts from 0, and then increases in turn: SUN=0, MON=1, TUE=2, ... Of course, we can also explicitly specify the enumeration value.

1.2 Three methods and essence of enumeration

  Use the enumeration type to define variables. The usage method is similar to that of structure and union. The three commonly used methods are as follows.
insert image description here
  An enum is a type, which is an integral type. The enumeration value list defined by enum is actually a set of integer sequences starting from 0. The variables we define using enumeration types can also be used as function parameters and function return values, can be used to define arrays, and even be mixed with structures. Enumeration is a bit like typedef, adding an alias to a value makes the program more intuitive and readable.
insert image description here
insert image description here
  Enumeration variables and integer variables can be assigned to each other, and they can be compiled and run normally. The variables of the enumeration type we use in the code will be replaced by integer values ​​in the executable file generated by the final compilation.
  The enumeration is similar to the preprocessing directive #define, both to increase the readability of the code. In the preprocessing stage, the macros are all replaced by simple string replacement. The compiler does not know that there are macros at all, and the enumeration types are all replaced with integers in the compilation stage. The advantage of enumerations is that enumerations can be automatically assigned, while macros need to be defined individually.

1.3 Three methods and essence of enumerationinsert image description here

  Most of the enumeration types defined by enum in the Linux kernel have no enumeration name, and usually an element prefixed with NR_ is added after a string of enumeration values ​​to indicate the number of enumeration values. When we don't need to use an enumeration type to define an enumeration variable, the enumeration does not need a name. These unnamed enumeration types are actually equivalent to macro definitions. The last element NR or MAX is generally used to record the number of elements in the enumeration list, or as a boundary value for loop judgment.

2. Constants and variables

  The content of this chapter is how are constants and variables stored in memory? How to access them?

1.1 The nature of variables

  The essence of a variable name is actually an alias for a memory space. When the compiler compiles the program, the variable name is regarded as a symbol, and the symbol value is the address of the variable, and various symbols are stored in the symbol table. We can read and write the memory unit bound to it through the variable name instead of directly using the memory address. Accessing memory through variable names not only facilitates the writing of programs, but also greatly enhances the readability of programs.
insert image description here
  Assignment modification: In C language, a memory area that can store data is generally called an object, and an expression that operates on this memory, that is, an expression that refers to an object, is called an lvalue. Common lvalues ​​include variables, e[n], e.name, p->name, *e and other common expressions. However, such as array names, functions, enumeration constants, function calls, etc. cannot be used as lvalues, nor can they be used to modify objects.
insert image description here
  When a variable is used as an lvalue, it usually represents the address of the object. Our reference to the variable name is actually to perform various operations on the address area. A variable name, when used as an rvalue, usually represents the contents of an object.
insert image description here
  Different types of variables have different storage methods, scopes, and life cycles. When defining a variable, we can use keywords such as char, int, float, double, etc. to specify the type of the variable, plus the two integer qualifiers short and long, basically determine the location of the variable in memory. The size of the storage space. Sometimes we can also use some variable modification qualifiers to change the storage method of variables. Commonly used modifiers are auto, register, static, extern, const, volatile, restrict, typedef, etc. These modification qualifiers often determine the storage location, scope or life cycle of variables, so they are generally called storage class keywords. If a variable is modified with register, it is intended to tell the compiler that this variable will be used frequently. If possible, this variable can be stored in the register of the CPU to improve its read and write efficiency.
  In the program, the purpose of defining variables is to facilitate reading and writing of data stored in the memory, not directly through the address, but through the variable name to access the memory. According to the variable type we define, the compiler will allocate a suitable size of storage space and address alignment in memory. The essence of a variable name is actually an alias for a section of memory storage space. Through the variable name, this section of memory can be directly read and written.

1.2 Constant storage

.rodataConstants and constant expressions, the compiler will put them separately in a read-only data segment called   when compiling the program , we can use the objdump command to view them.
insert image description hereinsert image description here
  In C language, we often use the const keyword to modify a variable, indicating that the variable is read-only and cannot be modified. If we use the const keyword to modify an array, it means that the values ​​of all elements in the array cannot be modified. The variables i and j are modified with const and stored in the .rodata read-only data segment .

1.2 Constant folding

When there is a constant expression   in a C language program , the compiler will optimize the constant expression into a fixed constant value during compilation to save storage space. We call this compilation optimization constant folding.
insert image description hereinsert image description hereinsert image description here

During program compilation, the compiler will directly optimize the expression 2 3+5 4 into a constant 26, which will be stored in the data segment as the initial value of the global variable val. At memory address 0x21024, we can see that the value of the defined global variable val is 0x1a. After the constant expression 2 3+5 4 is compiled and optimized, the value of the expression value becomes 26, which is directly stored in the memory unit whose address is 0x21024.

Guess you like

Origin blog.csdn.net/qq_41866091/article/details/130595677