源码网商城,靠谱的源码在线交易网站 我的订单 购物车 帮助

源码网商城

你必须知道的C语言预处理的问题详解

  • 时间:2021-05-21 11:39 编辑: 来源: 阅读:
  • 扫一扫,手机访问
摘要:你必须知道的C语言预处理的问题详解
  C语言预处理器执行宏替换、条件编译和文件包含。通常采用以“#”为行首的提示。下面是C语言预处理的应用场合:  [b] 1.三字母词(Trigraph Sequences)[/b]   C源程序的字符集被包含在7位的ASCII字符集中,但是它是ISO 646-1983 Invariant Code Set的超集。为了让程序可以在缩减集(reduced set)中呈现出来,下面的三字母词会被替换成相应的单字符.
三字母词 单字符
??= #
??/ \
??' ^
??( [
??) ]
??! |
??< {
??> }
??- ~
  替换发生在任何其他处理之前。   例如:如果你尝试打印字符串"what??!"  
[u]复制代码[/u] 代码如下:
 printf("what??!\n");
  会得到字符串"what|"。   如果你这样注释代码,结果会让你意外:  
[u]复制代码[/u] 代码如下:
// Will the next line be executed?????????????/ a++;
  a++并不会执行。前提是你知道\的作用。   注意:由于编译器对ANSI C的支持不一样,有些编译器会把三字母词当普通字符处理,你需要给编译选项加上“-trigraphs”   [b]2.行拼接[/b]   以反斜杠"\"结尾的行会把该行和下一行拼接成一行(预处理器做的工作就是把该反斜杠'"\"和接着的换行字符'\n'删除)。['\'称为续行符]   例如你可以这样写
[u]复制代码[/u] 代码如下:
/\ * is a legal comment. *\ /
  [b]3.宏定义和展开[/b]   [b]a)简单宏替换[/b]   简单宏替换使程序中能用一个标识符来表示一个单词串,指令形式为:
[u]复制代码[/u] 代码如下:
#define 标识符 单词串
  标识符(称为宏名)被定义为后面的单词串;单词串(简称串)是任意以换行结束的用于替换程序中该标识符的正文。如果串太长需要写成多行,则除了最后一行外每一行末尾都要有一个续行符(即添加一个“\”后回车)。   注意:字符串常数中出现的与宏名相同的字符串不在替换之列。例如:
[u]复制代码[/u] 代码如下:
#define YES 1 printf("YES");            // 输出 YES,而不是1
  [b]b)带参数的宏替换[/b]   预处理指令的形式为:
[u]复制代码[/u] 代码如下:
#define    标识符(标识符,标识符,...,标识符)    单词串
  “标识符(标识符,标识符,...,标识符)”是被定义的宏,()外面的标识符称为宏名,()中的标识符是宏的形式参数;宏名与其后的()之间不能有空白符。   例如:  
[u]复制代码[/u] 代码如下:
#define max(a,b) ((a)>(b)? (a): (b))
  [b]♦操作符#和##[/b]     操作符#把其后的串变成双引号包围的串;     操作符##把两个标志符拼在一起,形成一个新的标识符
[u]复制代码[/u] 代码如下:
#define str(expr)    #expr #define cat(x,y)      x ## y int ab=12; printf(str(hello world!));      // 会被替换成 printf("hello world!"); printf("ab=%d\n", cat(a,b));        // 会被替换成 printf("ab=%d\n", ab);  输出 ab=12
  [b]♦宏替换时的顺序[/b]  
[u]复制代码[/u] 代码如下:
#include <stdio.h>  #define f(a,b)  a##b  #define g(a)   #a  #define h(a)   g(a)  int main()  {          printf("%s\n", h(f(1,2)));          printf("%s\n", g(f(1,2)));          return 0;  }
  输出结果是12和f(1,2)。为什么会这样呢,宏的解开不像函数,由里到外。   (1)在""内的宏名或宏参数名不被替换   (2)宏替换顺序:一个带参数的宏内部调用另一个宏,参数也是一个宏,则先替换外层的宏,再替换外层宏的参数,最后替换内层宏。   知道这些规则对于出现上面的结果就不难理解了。   温馨提示:在写带参数的宏替换指令时,推荐的做法时将单词串中的每一个参数都用()括起来,整个表达式也要用()括起来;否则,替换结果可能不是你想要的,例如:
[u]复制代码[/u] 代码如下:
#define sqr(x)    x * x // 如果程序中的宏的引用形式为 sqr(3.0+1.0);                // 经预处理后会被替换为 3.0 + 1.0 * 3.0 + 1.0
  结果与你的原意(3.0+1.0)*(3.0+1.0)不等价   c)取消宏定义
[u]复制代码[/u] 代码如下:
#undef 标识符
  会使宏名标识符失去定义。如果#undef 一个没有定义过的标识符  也不会引发错误。   [b]4.文件包含 [/b] 
[u]复制代码[/u] 代码如下:
#include <filename>     // 引用标准库的头文件(编译器将从标准库目录开始搜索) #include "filename"       // 引用非标准库的头文件(编译器将从用户的工作目录开始搜索) #include 标识符            // 标识符是由#define 定义的<filename>或"filename"的宏名
  [b]5.条件编译[/b]   条件编译指令格式如下:
[u]复制代码[/u] 代码如下:
if-line 正文 [#elif 常量表达式 正文] ... [#else 正文] #endif
  if-line为下面中的任意一种形式:   (1)#if 常量表达式   (2)#ifdef 标识符   (3)#ifndef 标识符   [b]♦defined操作符用来判断标识符是否定义过。形式如下:[/b]   defined identifier [b]或[/b]   defined (identifier)   [b]下面的[/b]   #ifdef identifier   #ifndef identifier   [b]等价于[/b]   #if defined identifier   #if ! defined identifier   [b]6.行控制[/b]   行控制指令有下列两种形式   [b](1)#line n "filename"[/b] [b]  (2)#line n[/b]   行控制预处理功能为其他产生C源程序的预处理程序(例如数据库系统中的宿主C预编译程序)在跟踪被处理程序(例如被宿主C预编译程序处理的扩展名为.pc的预编译源程序)的行号时提供方便,便于最终用户的源程序查错和该错。它会使编译器相信n(十进制正整数)为下一个源程序行的行号,“filename”会被当作当前文件名。   [b]7.生成错误[/b]   #error error_messageopt   让编译器输出错误信息error_message   [b]8.Pragmas[/b]   #pragma token-sequenceopt   #pragma是编译程序实现时定义的指令,它允许由此向编译程序传入各种指令。例如,一个编译程序可能具有支持跟踪程序执行的选项,此时可以用#pragma语句选择该功能。编译程序忽略其不支持的#pragma选项。#pragma提高C源程序对编译程序的可移植性。   [b]9.空指令[/b]   形如   #   没有任何作用   [b]10.预定义宏[/b]   C语言规范了5个固有的预定义宏,他们分别是   __LINE__  当前源程序的行号   __FILE__  正在编译的程序的文件名   __DATE__  编译的日期字符串,形如"Mmm dd yyyy"   __TIME__  编译的时间字符串,形如"hh:mm:ss"   __STDC__  如果__STDC__的内容是十进制常数1,则表示编译程序的实现符合标准C
  • 全部评论(0)
联系客服
客服电话:
400-000-3129
微信版

扫一扫进微信版
返回顶部