C语言第八章The Preprocessor

Preprocessor Directives(指令)

The C preprocessor uses the # directives to make substitutions in program source code before compilation.
For example, the line #include <stdio.h> is replaced by the contents of the stdio.h header file before a program is compiled.

Preprocessor directives and their uses:

#include Including header files.

#define, #undef Defining and undefining macros.

#ifdef, #ifndef, #if, #else, #elif, #endif Conditional compilation.

#pragma Implementation and compiler specific.

#error, #warning Output an error or warning message An error halts compilation.

Do NOT put a semicolon character at the end of a # directive.

The #include Directive

The #include directive is for including header files in a program. A header file declares a collection of functions and macros for a library, a term that comes from the way the collection of code can be reused.

Some useful C libraries are:
stdio input/output functions, including printf and file operations.
stdlib memory management and other utilities
string functions for handling strings
errno errno global variable and error code macros
math common mathematical functions
time time/date utilities

Corresponding header files for the libraries end with .h by convention(按照惯例). The #include directive expects brackets <> around the header filename if the file should be searched for in the compiler include paths.

A user-defined header file is also given the .h extension, but is referred to with quotation marks, as in “myutil.h”. When quotation marks are used, the file is searched for in the source code directory.
For example:

#include <stdio.h>
#include “myutil.h”

Some developers use .hpp extension for header files.
.hpp file extension seems to be convention for C++ header files. Both .h and .hpp are acceptable for both C and C++ headers, but .h should be for C and .hpp for C++

The #define Directive

The #define directive is used to create object-like macros for constants based on values or expressions.
#define can also be used to create function-like macros with arguments that will be replaced by the preprocessor.

Be cautious with function-like definitions. Keep in mind that the preprocessor does a direct replacement without any calculations, which can lead to unexpected results, as demonstrated with the following program:

#include <stdio.h>
#define PI 3.14
#define AREA(r) (PI*r*r)
int main() {
  float radius = 2;
  printf("%3.2f\n", PI);
  printf("Area is %5.2f\n", AREA(radius));
  printf("Area with radius + 1: %5.2f\n", AREA(radius+1));
  return 0;
}

Before compilation, the preprocessor expands every macro identifier. In this case, every occurrence of PI is replaced with 3.14 and AREA(arg) is replaced with the expression PIargarg. The final code sent to the compiler will already have the constant values in place.

Not what we may expect! However, if you consider that #define works strictly by replacing text, you will see that AREA(radius+1) becomes PIradius+1radius+1, which is 3.142+12+1.

The solution to this is to enclose each parameter in parentheses to obtain the correct order of operations.
For example:

#include <stdio.h>
#define PI 3.14
#define AREA(r) (PI*(r)*(r))
int main() {
  float radius = 2;
  printf("%3.2f\n", PI);
  printf("Area is %5.2f\n", AREA(radius));
  printf("Area with radius + 1: %5.2f\n", AREA(radius+1));
  return 0;
}

The code produces the output: Area with radius + 1: 28.26.

Formatting Preprocessor Directives

When using preprocessor directives, the # must be the first character on a line. But there can be any amount of white space before # and between the # and the directive.

If a # directive is lengthy, you can use the \continuation character to extend the definition over more than one line.

For example:

#include <stdio.h>
#define VERY_LONG_CONSTANT \
23.678901

#define MAX 100
#define MIN 0
#    define SQUARE(x) \
    x*x
int main() {
  printf("%d\n", VERY_LONG_CONSTANT * SQUARE(2));
  return 0;
}

There is a typo(错字) in the output, should be %f instead of %d.

Predefined Macro Definitions

In addition to defining your own macros, there are several standard predefined macros that are always available in a C program without requiring the #define directive:
__DATE__ The current date as a string in the format Mm dd yyyy
__TIME__ The current time as a string in the format hh:mm:ss
__FILE__ The current filename as a string
__LINE__ The current line number as an int value
__STDC__ 1

For example:

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

int main() {
  char curr_time[10];
  char curr_date[12];
  int std_c;

  strcpy(curr_time, __TIME__);
  strcpy(curr_date, __DATE__);
  printf("%s %s\n", curr_time, curr_date);
  printf("This is line %d\n", __LINE__);    
  std_c = __STDC__;
  printf("STDC is %d", std_c);
  
  return 0;
}

Conditional Compilation Directives

The #ifdef, #ifndef, and #undef Directives

The #ifdef, #ifndef, and #undef directives operate on macros created with #define.
For example, there will be compilation problems if the same macro is defined twice, so you can check for this with an #ifdef directive. Or if you may want to redefine a macro, you first use #undef.

The program below demonstrates these directives:

#include <stdio.h>

#define RATE 0.08
#ifndef TERM
  #define TERM 24
#endif

int main() {
  #ifdef RATE  /* this branch will be compiled */
    #undef RATE  
    printf("Redefining RATE\n");
    #define RATE 0.068
  #else  /* this branch will not be compiled */
    #define RATE 0.068
  #endif

  printf("%f  %d\n", RATE, TERM);

  return 0;
}

Because RATE is defined at the top, only the #ifdef clause will be compiled. The optional #else branch compiles when #ifdef RATE is false during preprocessing.
An #endif is required to close the block of code.

An #elif directive is like an else if and can be used to provide additional alternatives after #else.

Conditional Compilation Directives

Conditional compilation of segments of code is controlled by a set of directives: #if, #else, #elif, and #endif.

#include <stdio.h>

#define LEVEL 4

int main() {
  #if LEVEL > 6
    /* do something */
  #elif LEVEL > 5
    /* else if branch */
  #elif LEVEL > 4
    /* another else if */
  #else
    /* last option here */
  #endif

  return 0;
}

There are instances where such conditional compilation can be useful, but this type of code should be used sparingly.
The defined() preprocessor operator can be used with #if, as in:

#if !defined(LEVEL)
  /* statements */
#endif

The #if and if statement are not interchangeable. The #if is evaluated using data available to the preprocessor, which then sends only the true branch for compilation.

An if statement uses data provided at runtime with the possibility of branching to any else clause.

#ifdef xy is the same as #if defined (xy); #ifndef is the same as #if !defined (xy);

The ‘#pragma’ directive is the method specified by the C standard for providing additional information to the compiler, beyond what is conveyed in the language itself. The forms of this directive (commonly known as pragmas) specified by C standard are prefixed with STDC. You can learn more on: https://gcc.gnu.org/onlinedocs/cpp/Pragmas.html

Preprocessor Operators

The C preprocessor provides the following operators.

The # Operator

The # macro operator is called the stringification or stringizing operator and tells the preprocessor to convert a parameter to a string constant.
White space on either side of the argument are ignored and escape sequences are recognized.

#include <stdio.h>

#define TO_STR(x) #x

int main() {
  
  printf("%s\n", TO_STR( 123\\12 ));
  
  return 0;
}

The ## Operator

The ## operator is also called the token pasting operator because it appends, or “pastes”, tokens together.

#include <stdio.h>

#define VAR(name, num) name##num

int main() {
  int x1 = 125;
  int x2 = 250;
  int x3 = 500;
  
  printf("%d\n", VAR(x, 3));
  
  return 0;
}

例题

#include <stdio.h>
#define T 42
int main()
{
   int T = 8;
   printf("%d ", T);
   return 0;
}

Compile Error
Think of a macro is copy and pasted throughout the whole code where it appears. So here every T is replaced by 42. Then the line int 42 = 8; does not make any sense

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值