C语言之预处理

ANSI C预处理命令:
#define, #undef, #include, #if, #else, #elif, #endif, #ifdef, #ifndef, #line, #error, #pragma

ANSI C宏:
_LINE_:表示正在编译的文件的行号
_FILE_:表示在横在编译的文件的名字
_DATE_:表示编译时刻的日期字符串,例如“25 Dec 2007”
_TIME_:表示编译时刻的时间字符串,例如“12:30:35”
_STDC_:判断该文件是不是定义成标准C程序

*******宏定义*******

数值宏常量
const修饰的只读(数值)变量不能用于定义数组的维数(错误。经验证,const变量可以用于定义数组维数),也不能放在switch-case的case后面作选项。


字符串宏常量

定义路径
#define ENG_PATH_1 E:\English\listen_to_this\listen_to_this_3
#define ENG_PATH_2 "E:\English\listen_to_this\listen_to_this_3"
ENG_PATH_2相当于在ENG_PATH_1两边加双引号,即“ENG_PATH_1”。
Linux系统上用‘/’作路径分割符,Windows系统用‘/’。有些系统规定路径要用双反斜杠“\\”。

定义注释
试图用宏变量来开始或结束一段注释是不可取的,因为注释先于预处理指令被处理,比如
#define BSC //
BSC my single-line comment
当这一行被展开成//...时,注释已经处理完毕,此时再出现//...就是错误。

定义表达式
宏变量只是简单的替换,要注意表达式中的变量是否要加括号等。比如:
#define SQR(x) x*x
SQR(10+1)就变成 10+1*10+1。
宏函数被调用时是以实参代换行参,而不是值传递。

定义的宏变量或表达式里不能出现空格,否则空格前的部分被当成变量,空格后的部分被当成变量要替换的值。

#undef用于撤销宏定义

*******条件编译*******
形式一: ifdef, else, endif

#ifdef 标识符
程序段
#endif

#ifdef 标识符
程序段 1
#else
程序段 2
#endif

形式二: ifndef, else, endif

#ifndef 标识符
程序段
#endif

#ifndef 标识符
程序段 1
#else
程序段 2
#endif

形式三:if, else, elif, endif

#if 常量表达式
程序段 1
#else
程序段 2
#endif


*******文件包含*******
#include <filename> 到系统指定的路径中获取文件filename
#include "filename" 到当前目录中查找文件filename。若没有找到,则到系统指定的路径中寻找。

#include支持相对路径,其中'.'代表当前目录,'..'代表上层目录。

*******#error预处理*******
编译程序时,只要遇到#error就会生成一个编译错误的提示信息,并停止编译。
#error error-message-content
error-message-content不用加双引号。

*******#line预处理*******
#line number["filename"], filename可选
改变当前行数和文件名称
用途: 编译器对C源代码编译过程中会产生一些中间文件,通过这条指令,可以保证文件名是固定的,不会被这些中间文件代替,有利于进行分析。

*******#pragma预处理*******
设定编译器的状态或者指示编译器完成一些特定的操作,一般格式为: #pragma parameter, parameter为参数。

#pragma message
使编译器在编译信息输出窗口中输出相应的信息,比如 #pragma message("消息文本")。再比如:
#ifdef _X86
#pragma message("_X86 macro activated!")
#endif

#pragma code_seg
Usage: #pragma code_seg(["section-name"[,"section-class"]]),设置程序中函数代码存放的代码段。

#pragma once
只要在头文件的最开始加入这条指令就能保证头文件只被编译一次

#pragma hdrstop
表示 预编译头文件到此为止,后面的头文件不进行编译。

#pragma resource
Usage example: #pragma resource "*.dfm",表示把*.dfm文件中的资源加入工程。*.dfm中包括窗体外观的定义。

#pragma warning

#pragma comment
该指令将以个注释记录放入一个对象文件或可执行文件中。
lib关键字,可以帮我吗连如一个库文件,比如: #pragma comment(lib, "user32.lib"),该指令用来江user32.lib库文件加入到本工程中。
linker关键字,可以将一个链接选项放入目标文件中,你可以使用这个指令来代替有命令行传入的或者在开发环境中设置的链接选项,你也可以制定/include选项来强制包含某个对象,比如: #pragma comment(linker, "/include: _mySymbol")

#pragma pack
内存对齐: 字(e.g., char),双字(e.g., short),和四字(e.g., int)在自然边界上不需要在内存中对齐。 对字,双字和四字来说,自然边界分别是偶数地址,可以被四整除的地址,和可以被8整除的地址。跨边界的被认为是不对齐的,需要两次总线周期来访问内存。

比如
struct TestStruct1
{
char c1;
short s;
char c2;
int i;
}
假设c1的地址是0 (00000000),那么s的地址就是1 (00000001),c2的地址就是3 (00000003),i的地址就是4 (00000004)。但这种存储中s和i都是跨界存储的。实际上编译器会对这些数的存储地址进行对齐,最后的存储地址是: c1 (00000000), s (00000002), c2 (00000004), i (00000008)。 sizeof(TestStruct1)不为8,而是12。

若将TestStruct1调整如下,则可以节省一点空间(4字节):
struct TestStruct2
{
char c1;
char c2;
short s;
int i;
}
这样,每个成员都对齐在其自然边界上,从而避免了编译器的自动对齐。sizeof(TestStruct2)为8。

#pragma pack(n),编译器从此处开始将按照n个字节对齐。
#pragma pack(),编译器从此处开锁取消自定义字节对齐方式。
而在#pragma pack(n)和#pragma pack()之间的代码按n个字节对齐。
对齐规则是: 每个成员按其类型的对齐参数(通常是这个类型的大小)和制定对齐参数(这里是n字节)中较小的一个对齐,并且结构的长度必须为所用过的所有对齐参数的整数倍,不够就补空字节。 对于复杂类型成员(比如结构)来说,他的默认对齐方式就是按照他的所有成员使用的对齐参数中的最大值。

#pragma pack(push):保存当前的对齐方式刀packing stack中
#pragma pack(pop):packing stack出栈,并将对齐方式设置为出栈的对齐方式。
#pragma pack(push, n)相当于 #pragma pack(push)和 #pragma pack(n)


*******#运算符*******
#define SQR(x) printf("The square of x is %d.\n", ((x)*(x)));
SQR(8)为: The square of x is 64.

#define SQR(x) printf("The square of "#x" is %d.\n", ((x)*(x)));
SQR(8)为:  The square of 8 is 64.

*******##运算符*******
##将两个语言符号组合成单个语言符号,比如:
#define XNAME(n)    x ## n
XNAME(8)为: x8。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值