汕头百度网站建设,怎样建设网站免费,铜陵58同城做网站,wordpress显示文章时分秒代码文章目录 3.2.7 命名约定 3.3 #undef3.4 命令行定义3.5 条件编译3.6 文件包含3.6.1 头文件被包含的方式3.6.2 嵌套文件包含 4. 其他预处理指令 3.2.7 命名约定
一般来讲函数和宏的使用语法很相似#xff0c;所以语言本身没法帮我们区分二者#xff0c;那我们平时的一个习惯是… 文章目录 3.2.7 命名约定 3.3 #undef3.4 命令行定义3.5 条件编译3.6 文件包含3.6.1 头文件被包含的方式3.6.2 嵌套文件包含 4. 其他预处理指令 3.2.7 命名约定
一般来讲函数和宏的使用语法很相似所以语言本身没法帮我们区分二者那我们平时的一个习惯是 把宏名全部大写 函数名不要全部大写 #define MAX(x, y) ((x)(y)?(x):(y))int Max(int x, int y)
{return x y ? x : y;
}//有一个特例
//offsetof - 宏 - 全小写int main()
{return 0;
}3.3 #undef
这条指令用于移除一个宏定义。 #undef NAME //如果现存的一个名字需要被重新定义那么它的旧名字首先要被移除。 #include stdio.h#define MAX(x, y) ((x)(y)?(x):(y))int Max(int x, int y)
{return x y ? x : y;
}int main()
{int c MAX(3, 5);printf(%d\n, c);
#undef MAXc MAX(5, -5);//编译器会报错“MAX”未定义printf(%d\n, c);return 0;
}3.4 命令行定义
许多C的编译器提供了一种能力允许在命令行中定义符号用于启动编译过程。
例如当我们根据同一个源文件要编译出一个程序的不同版本的时候这个特性有点用处。假定某个程序中声明了一个某个长度的数组如果机器内存有限我们需要一个很小的数组但是另外一个机器内存大些我们需要一个数组能够大些。
注VS环境无法演示gcc来演示
#include stdio.hint main()
{int arr [SZ];int i 0;for(i 0; i SZ; i){arr[i] i 1;}for(i 0; i SZ; i){printf(%d , arr[i]);}return 0;
}3.5 条件编译
在编译一个程序的时候我们如果要将一条语句一组语句编译或者放弃是很方便的因为我们有条件编译指令。
比如我们要在不同的操作系统上执行代码那么就要执行不同的代码我们就可以使用条件编译满足相应的条件就编译相应的代码另外一份代码就不会被编译了。
常见的条件编译指令 #if 常量表达式 //… #endif //常量表达式由预处理器求值。 #include stdio.h#define M 0int main()
{
#if 1 M //#if 后面的语句为真就参与编译否则就不参与编译printf(hehe\n);
#endifreturn 0;
}注 #if 条件编译不满足是不编译而 if 条件语句不满足是不执行但是它的代码运行时是存在的。
多个分支的条件编译 #if 常量表达式 //… #elif 常量表达式 //… #else //… #endif #include stdio.h#define M 0int main()
{
#if 1 Mprintf(hehe\n);
#elif 2 Mprintf(haha\n);
#elseprintf(heihei\n);
#endifreturn 0;
}判断是否被定义 #if defined(symbol) #ifdef symbol #if !defined(symbol) #ifndef symbol #include stdio.h#define WIN 0int main()
{
#if defined(WIN)printf(windows);
#endifreturn 0;
}也可以这样写
#include stdio.h#define WIN 0int main()
{
#ifdef WINprintf(windows);
#endifreturn 0;
}#include stdio.h#define WIN 0int main()
{
#if !defined(WIN)printf(windows\n);
#endifreturn 0;
}也可以这样写
#include stdio.h#define WIN 0int main()
{
#ifndef WINprintf(windows\n);
#endifreturn 0;
}嵌套指令
#if defined(OS_UNIX)#ifdef OPTION1unix_version_option1();#endif#ifdef OPTION2unix_version_option2();#endif
#elif defined(OS_MSDOS)#ifdef OPTION2msdos_version_option2();#endif
#endif我们在 stdio.h 这个头文件中就能看到条件编译的应用 有些人会将条件编译当注释来用
#if 0
int main()
{return 0;
}
#endif#include stdio.hint main()
{printf(hehe\n);return 0;
}3.6 文件包含
我们已经知道 #include 指令可以使另外一个文件被编译就像它实际出现于 #include 指令的地方一样。
这种替换的方式很简单
预处理器先删除这条指令并用包含文件的内容替换。
这样一个源文件被包含10次那就实际被编译10次。
3.6.1 头文件被包含的方式
本地文件包含 #include “filename” 查找策略先在源文件所在目录下查找如果该头文件未找到编译器就像查找库函数头文件一样在标准位置查找头文件如果找不到就提示编译错误。
Linux环境的标准头文件的路径 /usr/include VS环境的标准头文件的路径 C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include //这是VS2013的默认路径 注意按照自己的安装路径去找。 库文件包含 #include filename.h 查找头文件直接去标准路径下去查找如果找不到就提示编译错误。
这样是不是可以说对于库文件也可以使用 “” 的形式包含
答案是肯定的可以。
但是这样做查找的效率就低些当然这样也不容易区分是库文件还是本地文件了。
3.6.2 嵌套文件包含
如果出现这样的场景 comm.h和comm.c是公共模块。
test1.h和test1.c使用了公共模块。
test2.h和test2.c使用了公共模块。
test.h和test.c使用了test1模块和test2模块。
这样最终程序中就会出现两份comm.h的内容。这样就造成了文件内容的重复。
例子如下
如何解决这个问题
答案条件编译。
每个头文件的开头写
#ifndef __TEST_H__
#define __TEST_H__
//头文件的内容
#endif //__TEST_H__或者
#pragma once就可以避免头文件的重复引入。
例子
//test.h#ifndef __TEST_H__
#define __TEST_H__int Add(int x, int y);#endif或者这样写
//test.h#pragma onceint Add(int x, int y);4. 其他预处理指令 #error #pragma #line … 不做介绍自己去了解。 #pragma pack()在结构体部分介绍。