preface

C execution process 1, compilation: the formation of object code 2, link: the object code and C function library link, merge the code, generate executable files. 3, run,

Example:

Test.txt


printf("I love coding\n");
Copy the code

main.c


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

 int main(a){
     // Precompile: Copy the complete code of the file directly in preparation for compilation (replace)
     // Before compiling, do something
     //#include "test.txt" equals printf("I have a Dream.");
     #include "Test.txt"
     getchar(a);return 0;
 }
Copy the code

Result output:

I love coding
Copy the code

C preprocessor

The C preprocessor is not part of the compiler, but it is a separate step in the compilation process. In short, the C preprocessor is nothing more than a text-replacement tool that instructs the compiler to do the required preprocessing before the actual compilation. We will abbreviate the C Preprocessor to CPP. All preprocessor commands begin with a pound sign (#). It must be the first non-null character, and for readability, preprocessor instructions should start from the first column. All important preprocessor instructions are listed below:

instruction describe
#define Define the macro
#include Contains a source code file
#undef Cancels defined macros
#ifdef Returns true if the macro is already defined
#ifndef Returns true if the macro is not defined
#if If the given condition is true, the following code is compiled
#else #if Alternatives to
#elif If the previous #if given condition is not true and the current condition is true, compile the following code
#endif End a #if… #else conditional compiler block
#error When a standard error is encountered, an error message is printed
#pragma Use standardized methods to issue special commands to the compiler

Macro definition, macro replacement

1. Define the identity
(1) For example, to determine whether a certain syntax, platform, etc., is supported by judging whether some identifiers are defined:

// indicates support for C++ syntax


#ifdef __cplusplus

#endif // __cplusplus
Copy the code

// Indicates support for Android, Windows, Apple, etc


#ifdef ANDROID

#endif // ANDROID
Copy the code
(2) Prevent repeated introduction of header files:

For example, we have three files a.h, b.h, and test.cpp, as follows:

This is the a.h:


#include "b.h"

void a(a);
Copy the code

This is the b.h:


#include "a.h"

void b(a);
Copy the code

Finally, test. CPP references a.H.


#include "a.h"
Copy the code

Thus, when Test contains a, A contains B, and B contains A, creating a loop of inclusion. Similar to the SQL circular reference in Hibernate. The following error will be reported:


Fatal Error C1014: Contains too many files: depth =1024
Copy the code

This problem can be solved by macro definition judgment: A.H.


#ifndef AH // if AH is not specified, only the following statement will be executed. If AH is defined, the following statement will not be executed
#define AH
#include "B.h"
void printfA(a);

#endif
Copy the code

B.h


#ifndef BH
#define BH
#include "A.h"
void printfB(a);

#endif
Copy the code

In addition, the new version solves this problem with the #pragma once statement.


// The header is included only once, and the compiler handles loop inclusion automatically
#pragma once
#include "B.h"
Copy the code
2. Define constants (easy to modify and read)

#define MAX 100

void main(a){
    int i = 100;
    if (i == MAX){
        printf("Ha ha");
    }
    getchar(a); }Copy the code
3. Define “macro functions”.

It’s essentially a substitution process.

Example:

#include <stdio.h>
#include <stdlib.h>

#define GET_MIN(A,B) A < B ? A : B

 int main(a){
     int a = 100;
     int b = 200;
     int c = GET_MIN(100.200);
     printf("Minimum value: %d\n", c);
     getchar(a);return 0;
 }
Copy the code

Result output:

Minimum value: 100Copy the code
An example of a simplified Android LOG:

C language macro function print statement simple use:


#define LOG(FORMAT,...) printf(FORMAT,__VA_ARGS__);
Copy the code

. Three dots indicate that the variable argument has a LOG level corresponding to __VA_ARGS__, thus further upgrading:


#define LOG_I(FORMAT,...) printf("INFO:"); printf(##FORMAT,__VA_ARGS__);
#define LOG_E(FORMAT,...) printf("ERROR:"); printf(##FORMAT,__VA_ARGS__);
Copy the code

To further simplify duplicate code, repeat LEVEL log LEVEL:


#defineLOG(LEVEL,FORMAT,...) printf(LEVEL); printf(##FORMAT,__VA_ARGS__);
#defineLOG_I(FORMAT,...) LOG("INFO:",FORMAT,__VA_ARGS__);
#defineLOG_E(FORMAT,...) LOG("ERROR:",FORMAT,__VA_ARGS__);
#defineLOG_D(FORMAT,...) LOG("DEBUG:",FORMAT,__VA_ARGS__);
Copy the code

When Android JNI was being developed, we printed a log sentence using the __android_log_print function


__android_log_print(ANDROID_LOG_INFO, "FFmpeg"."%s"."fix");
Copy the code

In the same way, practical use simplifies code by defining macros:


#define LOGI(FORMAT,...) __android_log_print(ANDROID_LOG_INFO,"FFmpeg",FORMAT,##__VA_ARGS__);
LOGI("%s"."fix");
Copy the code

Predefined macro

ANSI C defines many macros. You can use these macros in programming, but you cannot directly modify the predefined macros.

The macro describe
__ DAT__ The current date, a character constant in the format “MMM DD YYYY”.
__ TIME__ The current time, a character constant in “HH:MM:SS” format.
__ FILE__ This will contain the current filename, a string constant.
__ LINE__ This will contain the current line number, a decimal constant.
__ STDC__ Is defined as 1 when the compiler compiles to ANSI standards.

Let’s try the following example:


#include <stdio.h>

main()
{
   printf("File :%s\n", __FILE__ );
   printf("Date :%s\n", __DATE__ );
   printf("Time :%s\n", __TIME__ );
   printf("Line :%d\n", __LINE__ );
   printf("ANSI :%d\n", __STDC__ );

}
Copy the code

When the above code (in file test.c) is compiled and executed, it produces the following results:


File :test.c
Date :Jun 2 2012
Time :03:36:24
Line :8
ANSI :1
Copy the code

Preprocessor operator

The C preprocessor provides the following operators to help you create macros: macro continuation operator (\) A macro is usually written on a single line. But if the macro is too long to fit on a single line, the macro continuation operator (\) is used. Such as:


#define  message_for(a, b)  \
    printf(#a " and " #b ": We love you! \n")
Copy the code
String constant quantization operator#
In macro definitions, the string constant quantization operator is used when a macro parameter needs to be converted to a string constant#. The operator used in macros has a specific argument or argument list. Such as:

#include <stdio.h>

#define  message_for(a, b)  \
    printf(#a " and " #b ": We love you! \n")

int main(void)
{
   message_for(Carole, Debra);
   return 0;
}
Copy the code

When the above code is compiled and executed, it produces the following results:


Carole and Debra: We love you!
Copy the code
Tag paste operator# #
The mark-paste operator within the macro definition# #Two parameters are merged. It allows two independent tags to be combined into a single tag in a macro definition.
Example 1

#include <stdio.h>

#define tokenpaster(n) printf ("token" #n " = %d", token##n)

int main(void)
{
   int token34 = 40;
   
   tokenpaster(34);
   return 0;
}
Copy the code

Result output:

token34 = 40
Copy the code

Because this example produces the following actual output from the compiler:


printf ("token34 = %d", token34);
Copy the code

This example demonstrates that token##n will be connected to token34, where we use the string constant quantization operator # and the tag paste operator ##.

Example 2

 #include <stdio.h>
 // Method names are long (method names are regular)
  int com_haocai_ndk_get_min(int a,int b){
      return a < b ? a : b;
  }

  int com_haocai_ndk_get_max(int a,int b){
      return a > b ? a : b;
  }
  // Syntax specification
  / / # define labeled NAME (the method NAME, A, B) com_tz_ndk_get_ # # NAME (A, B)
  #define call(NAME,A,B) com_haocai_ndk_get_##NAME(A,B)

  int main(a){
      int c = call(min,100.200);
      printf("Minimum value :%d\n",c);
      int d = call(max,100.200);
      printf("Max :%d\n",d);
      getchar(a);return 0;
  }
Copy the code

Result output:

Minimum value :100 Maximum value :200Copy the code
The defined () operator

The preprocessor defined operator is used in constant expressions to determine whether an identifier has already been defined using #define. The value is true (non-zero) if the specified identifier is defined. If the specified identifier is not defined, the value is false (zero). The following example demonstrates the use of the defined() operator:


#include <stdio.h>

#if! defined (MESSAGE)
   #define MESSAGE "You wish!"
#endif

int main(void)
{
   printf("Here is the message: %s\n", MESSAGE);  
   return 0;
}
Copy the code

When the above code is compiled and executed, it produces the following results:


Here is the message: You wish!
Copy the code
Parameterized macros

A powerful feature of CPP is the ability to simulate functions using parameterized macros. For example, the following code calculates the square of a number:


int square(int x) {
   return x * x;
}
Copy the code

We can rewrite the above code using macros as follows:


#define square(x) ((x) * (x))
Copy the code

Before using a macro with parameters, you must use the #define directive. The argument list is enclosed in parentheses and must be immediately followed by the macro name. No Spaces are allowed between the macro name and the opening parenthesis. Such as:


#include <stdio.h>

#define MAX(x,y) ((x) > (y) ? (x) : (y))

int main(void)
{
   printf("Max between 20 and 10 is %d\n".MAX(10.20));  
   return 0;
}.
Copy the code

When the above code is compiled and executed, it produces the following results:


Max between 20 and 10 is 20
Copy the code