C语言学习笔记(五) 预处理符号

关于预处理的“常识”

  • 预处理并不是编译,也不是“预编译”。
  • 预处理并不是每个语言都有的。
  • C/C++预处理仅仅是把源程序划分和整理成一个个的段(phase),并不进行编译。
  • 预处理器在UNIX传统中通常缩写为PP,在自动构建脚本中C预处理器被缩写为CPP的宏指代。为了不造成歧义,C++(c-plus-plus) 经常并不是缩写为CPP,而改成CXX。

C语言预处理符号

ANSI C标准要求支持的预处理符号包括:

#define、#undef(宏定义), #include(文件包含), #if、#else、#elif、#endif、#ifdef、#ifndef(条件编译), #line(行控制), #error(错误处理), #pragma(实现相关), #(转义),##(参数连接)。

宏定义的注意事项

试图使用宏去定义注释符号是不行的,例如以下代码:

    #define BSC //
    #define BMC /*
    #define EMC */
    BSC my single-line comment
    BMC my multi-line comment EMC

因为注释先于预处理指令处理,当展开这些宏定义的时候自然会出现一堆错误。

宏定义表达式的时候一定不能吝啬括号这个不用解释了。

宏定义的时候宏名中最好不要有空格。下面的定义会带来很多麻烦:

    #define SUM (x) ((x)*(x))

一旦使用了#undef撤销宏,则后面的代码都不能使用这个宏,除非再次定义。此外,如果没有#undef的情形下就直接再次定义,后来的定义会覆盖掉前面的定义。下面代码中的c值是4:

    #include <stdio.h>

    #define X 3
    #define Y X*2
    #undef X
    #define X 2

    int c = Y;

    int main(int argc, char** argv){
        printf("%d",c) ;
        return 0;
    }

宏仅在使用的时候展开,否则即使定义有问题,也不会编译出错。如果把上面代码中的第二个#define注释掉,并把C的值赋值为0,即撤销了X定义,也不会报错,因为没有使用Y,也就不会展开。

#pragma的常用参数

message:用于在编译窗口输出信息中显示对应信息。下面是一个典型的应用:

    #ifdef _X86
        #pragma message("x86 macro is activated.");
    #endif

code_seg:在开发驱动程序的时候会用到。

once: 指定(确保)仅编译一次该文件(一般是头文件)。

hdrstop:表示不编译后面的头文件。

pack:指定内存对齐参数。

#符号和##符号

#符号用于转义。这么说起来不好理解,看例子:

    #define PRTSQR(x) printf("The sqr of x is %d.\n", ((x)*(x)));

如果执行PRTSQR(4),则这句代码的输出是:

The sqr of x is 16.

如果希望显示参数的值,那么在字符串中的字符x前面加一个#并加一个引号,即:

    #define PRTSQR(x) printf("The sqr of "#x" is %d.\n", ((x)*(x)));

输出结果就成了:

The sqr of 4 is 16.

##运算符用于连接,例如下面的宏:

    #define XNAME(n) x##n
    int XNAME(8);

上面的第二行代码会被展开为x8。

关于预处理符号先总结到这里。

时间: 2024-08-02 12:06:41

C语言学习笔记(五) 预处理符号的相关文章

【GO】GO语言学习笔记五

函数 1.函数的基本组成 关键字func,函数名,参数列表,返回值,函数体,返回语句. 2.函数的定义 举个栗子 package mymath import "errors" func Add(a int, b int) (ret int, err error) { if a < 0 || b < 0 { // 假设这个函数只支持两个非负数字的加法 err= errors.New("Should be non-negative numbers!") re

C语言学习笔记(五) 数组

数组 数组的出现就是为了解决大量同类型数据的存储和使用的问题: 数组的分类:一维数组.二维数组. 一维数组:为多个变量连续分配存储控件:所有的变量的数据类型必须相同:所有变量所占的字节大小必须相等: 例如:int a[4]; 一维数组名不代表数组中的所有元素而是代表数组中第一个元素的地址: 数组的初始化: 完全初始化: int a[4] = {1,2,3,4}; 不完全初始化: int a[4] = {1};  未被初始化的元素的值默认为0; 数组清零 int a[4] = {0}; 不初始化:

R语言学习笔记

參考:W.N. Venables, D.M. Smith and the R DCT: Introduction to R -- Notes on R: A Programming Environment for Data Analysis and Graphics,2003. http://bayes.math.montana.edu/Rweb/Rnotes/R.html 前言:关于R 在R的官方教程里是这么给R下注解的:一个数据分析和图形显示的程序设计环境(A system for data

Linux System Programming 学习笔记(五) 进程管理

1. 进程是unix系统中两个最重要的基础抽象之一(另一个是文件) A process is a running program A thread is the unit of activity inside of a process the virtualization of memory is associated with the process, the threads all share the same memory address space 2. pid The idle pro

R语言学习笔记2——绘图

R语言提供了非常强大的图形绘制功能.下面来看一个例子: > dose <- c(20, 30, 40, 45, 60)> drugA <- c(16, 20, 27, 40, 60)> drugB <- c(15, 18, 25, 31, 40) > plot(dose, drugA, type="b") > plot(dose, drugB, type="b") 该例中,我们引入了R语言中第一个绘图函数plot.pl

小猪的数据结构学习笔记(五)

小猪的数据结构学习笔记(五) 线性表之--循环链表                           --转载请注明出处:coder-pig 循环链表知识点归纳: 相关代码实现: ①判断是否为空表: ②单循环链表的存储结构 其实和单链表的结构是一样的! /*定义循环链表的存储结构*/ typedef struct Cir_List { int data; struct Cir_List *next; }Lnode; ③初始化循环单链表 代码如下: //1.循环链表的初始化 //表示一个元素,如

Go语言学习笔记(二) [变量、类型、关键字]

日期:2014年7月19日 1.Go 在语法上有着类 C 的感觉.如果你希望将两个(或更多)语句放在一行书写,它们 必须用分号分隔.一般情况下,你不需要分号. 2.Go 同其他语言不同的地方在于变量的类型在变量名的后面.例如:不是,int a,而是 a int.当定义了一个变量,它默认赋值为其类型的 null 值.这意味着,在 var a int后,a 的 值为 0.而 var s string,意味着 s 被赋值为零长度字符串,也就是 "". 3.Go语言的变量声明和赋值 在Go中使

Swift学习笔记五:循环和条件语句

一.循环语句 1. for循环 1) for -in 循环,对于数据范围,序列,集合等中的每一个元素,都执行一次 for a in 0...5{}    //循环迭代,从a=0到a=5,执行{}里的代码 注意:a只循环中存在,也就是出了{}a就不存在了 或者遍历数组 let a = [1,2,3] for b in a{} //循环迭代,从b=1到b=3 如果你不需要序列中的每一个值,可以使用_来忽略它,仅仅只是使用循环体本身: for _ in 0...5{}    //循环执行{}里的代码,

深度学习笔记(五):LSTM

深度学习笔记(一):logistic分类 深度学习笔记(二):简单神经网络,后向传播算法及实现 深度学习笔记(三):激活函数和损失函数 深度学习笔记(四):循环神经网络的概念,结构和代码注释 深度学习笔记(五):LSTM 看到一篇讲LSTM非常清晰的文章,原文来自Understanding LSTM Networks , 译文来自理解LSTM网络 Recurrent Neural Networks 人类并不是每时每刻都从一片空白的大脑开始他们的思考.在你阅读这篇文章时候,你都是基于自己已经拥有的