gcc conditional compilation, structure and memory management

Suffixes supported by gcc

.c C original program
.C/.cc/.cxx C++ original program
.m Objective-C original program
.i preprocessed original C program
.ii Preprocessed C++ original program
.s/.S Assembly language original program
.h preprocessing file (header file)
.o object file
.a/.so Compiled library files

Basic usage and options of GCC

 The most basic usage of Gcc is: gcc [options] [filenames]
-c, only compiling, not linking into an executable file, the compiler only generates an object file with a suffix of .o from the input source code files such as .c, and is usually used to compile subroutine files that do not contain the main program.
-o output_filename, determine the name of the output file as output_filename, and this name cannot be the same as the source file. If this option is not given, gcc will give the default executable file a.out.
-g, generate the symbolic information necessary for the symbolic debugging tool (GNU's gdb). To debug the source code, we must add this option.
-O, optimize the compilation and connection of the program. With this option, the entire source code will be optimized during compilation and connection, so that the execution efficiency of the generated executable file can be improved.
However, the speed of compiling and linking is correspondingly slower.
-O2, better optimized compilation and connection than -O, of course the entire compilation and connection process will be slower.
-I dirname, add the directory indicated by dirname to the program header file directory list, which is a parameter used in the precompilation process.
-L dirname, add the directory indicated by dirname to the directory list of the program function archive file, which is a parameter used in the linking process.

Generate preprocessing code

$ gcc –E test.c -o test.i
Use the wc command to view the code size of these two stages:
$ wc test.c test.cpp
9 16 127 test.c
842 1934 16498 test.cpp
851 1950 16625 Total usage
test.i has a lot more content than test.c, mainly in the include file provided by the system

Generate assembly code

Check for syntax errors and generate assembly files
$ gcc –S test.c –o test.s

Generate object code

Method 1, use gcc to directly generate object code from C source code:
$ gcc –c test.s –o test.o
 Method 2, using an assembler to generate object code from assembly code:
$ as test.s –o test.o

Generate executable program

 Link the target program to the library resource to generate an executable program
$ gcc test.s –o test

Conditional compilation

 1. According to whether the macro is defined or not, its syntax is as follows:
#ifdef <macro>
 ...
#else
  ...
#endif
 2. According to the value of the macro, its syntax is as follows:
#if <macro>
  ...
#else
...
#endif

Structure

Example:
Define a worker worker structure as follows:
struct worker
{<!-- -->
long number;
char name[20];
char sex;
int age; // age is the member name
float salary;
char address[80];
}; // Note that the semicolon cannot be omitted
int age = 10; //age is the variable name

Define variables at the same time as defining the type
The general form of a definition of this form is:
struct structure name
{<!-- -->
 member list;
\t\t}variable name; 

Structure Size

sizeof (computation volume)

Initialization of structure variables

struct structure name variable name={<!-- -->initial data table};
The other is to initialize the structure variable when defining the structure type.
struct structure name
{<!-- -->
member list;
} variable name = {<!-- --> initial data table};

Structure Array

1. Define the structure type first, and then use it to define the structure array.
The definition form of the structure array is as follows:
struct structure name
{<!-- -->
member list;
};
struct structure name
\t
\tFor example:
struct student
{<!-- -->
char name[20];
char sex;
int age;
char addr[20];
};
struct student stu[3];

Community

For example:
union gy
{<!-- -->
int i;
char c;
float f;
};
Here, a union type union gy is defined, which consists of three members, and these three members use a common storage space in memory. Since the data length of each member in the union is often different, the memory space of the member with the largest data length among the members is always occupied when the union variable is stored.


In this regard, the union body is different from the structure body, and the structure type variable always occupies the memory space according to the sum of the data length of each member when storing.
For example, a struct type is defined:
struct gy
{<!-- -->
  int i;
  char c;
  float f;
};
Then the memory size occupied by the variable of structure type struct gy is 2 + 1 + 4=7 bytes (regardless of byte alignment).

In the program, the form of mutual nesting of structures and unions is often used.
That is, a member of a union type can be a structure type, or a member of a structure type can be a union type.
For example, the third member of the following structure type datas is a union type:
struct data
{<!-- -->
   char *ps;
   int type;
   union
   {<!-- -->
     float fdata;
     int idata;
     char cdata;
    }udata;
};


typedef

In the C language, it is allowed to use the keyword typedef to define new data types
    Its syntax is as follows:
typedef <existing data type> <new data type>;
like:
typedef int INTEGER;
Here the data type INTEGER is newly defined, which is equivalent to int
INTEGER i; <==> int i;
\t     
In C language, typedef is often used when defining structure types, for example
typedef struct _node_
{<!-- -->
     int data;
     struct _node_ *next;
} listnode, *linklist;
Two new data types listnode and linklist are defined here.
Where listnode is equivalent to data type struct _node_ and linklist is equivalent to struct _node_ *

Memory management

 C/C++ defines 4 memory ranges:
 Code area/global variable and static variable area/local variable area are stack area/dynamic storage area is heap area.
 \t
static memory allocation
Variables are usually defined, and the compiler can know the size of the required memory space according to the type of the variable at compile time, so that the system allocates a certain storage space for them at an appropriate time.
Created on the stack. When a function is executed, the storage units of local variables in the function can be created on the stack, and these storage units are automatically released when the function execution ends. The stack memory allocation operation is built into the instruction set of the processor, which is very efficient, but the allocated memory capacity is limited.
\t 
Dynamic Storage Allocation
Some operation objects can only be determined when the program is running, so the compiler cannot reserve storage space for them when compiling, and the system can only allocate memory according to the requirements of the runtime when the program is running. This method is called.
All dynamic storage allocations take place on the heap.
Allocation from the heap, also known as dynamic memory allocation. When the program is running, use malloc to apply for any amount of memory, and the programmer is responsible for when to release the memory with free. The lifetime of dynamic memory is determined by us, and it is very flexible to use, but it also has the most problems.
\t
Heap memory allocation and release
When the program runs to a variable or object that needs to be dynamically allocated, it must apply to the system for a piece of storage space of the required size in the heap to store the variable or object. When the variable or object is no longer used, that is, when its life ends, the storage space occupied by it must be explicitly released, so that the system can re-allocate the heap space to reuse limited resources.
The heap area is not automatically initialized (including cleared) when it is allocated, so it must be explicitly initialized with an initializer.

malloc/free
    void * malloc(size_t num)
    void free(void *p)
The malloc function itself does not identify what type of memory to apply for, it only cares about the total number of bytes in the memory.
What malloc applies for is a piece of contiguous memory, which may sometimes be larger than the requested space. It sometimes fails to apply for memory and returns NULL.
The type of the return value of malloc is void *, so when calling malloc, type conversion must be performed explicitly to convert void * to the required pointer type.
If the parameter of free is NULL, it has no effect.
Freeing part of a block of memory is not allowed.


malloc/free notes:

The lifetime of a dynamically allocated variable or object. The lifetime of an unnamed object does not depend on the scope in which it was created. For example, a dynamic object created in a function can still be used after the function returns. We also call heap space as free space (free store) for this reason. But you must remember to release the heap space occupied by the object, and it can only be released once. It is easy to get out of control when it is created inside the function, and it is often wrong.

malloc/free wild pointer:

 is not a NULL pointer, but a pointer to "garbage" memory. "Wild pointer" is very dangerous. There are two main causes of "wild pointers":
 Pointer variable is not initialized.
 After the pointer p is freed, it is not set to NULL, making people mistakenly think that p is a legal pointer.
 Pointer operations go beyond the scope of variables. This situation is unpredictable.