目录
一,条件编译使用分析
-
条件编译控制预编译器保留某些代码,删除某些代码。
-
条件编译的行为类似于C语言中if...else...语句。
条件编译语句:#if...#else...#endif
#include <stdio.h>
int main()
{
const char* s;
#ifdef C
s = "This is first printf...\n";
#else
s = "This is second printf...\n";
#endif
printf("%s", s);
return 0;
}
如果定义了宏define C, 则执行if语句。
条件编译本质:
-
预编译器根据条件编译指示可以删除保留代码。
-
条件编译在预编译期进行分支判断。
插入知识点1:可以通过预编译器命令行定义宏。
gcc -Dmacro = value file.c
(宏名称)
或者:
gcc -Dmacro file.c
(file.c代表编译的文件名)
例如在上面语句中,输出结果为this is second printf...
如果此时我们在预编译系统的命令行加上:gcc -DC file.c
此时输出结果就变为this is first printf...
插入知识点2:#include本质
-
#include的本质就是将已经存在的文件嵌入到当前文件夹中。
-
#include的间接包含同样会产生嵌入内容的操作。
例如include<stdio.h>就是把stdio.h包含的代码复制到预处理器中进行处理。
如果调用头文件时,几个头文件都重复包含了某一段代码,那么编译就会产生错误。
解决办法有两个:
1,条件编译:(最常用)
//a.h
#includ<stdio.h>
#ifndef _A_H //_A_H命名与头文件对应
#define _A_H
...
#endif;
2,#pragma once
//a.h
#pragma once
#include<stdio.h>
...
注:在工程实际开发中,条件编译也常用来定义产品的发布版和调试版。
二,#error和#line使用分析
-
#error用于生成一个编译错误的消息
用法:
#error message
(message不需要双引号)
同样的,#warning用于生成编译警告,语句和#error一样。
#ifndef _cplusplus
#error this file should be processsed with C++ compiler
#endif
-
#line用于强制指定新行号和编译文件名,并对源程序代码重新编号。
用法:
#line unmber "filename"
(filename可以省略)
#line本质是重定义 _LINE_ 和 _FILE_
//test.c
#line 1 "qingshan"
#include<stdio.h>
int main()
{
printf("hello world\n")
return 0;
}
如果没有第三行的代码,编译后就会警告test.c文件的第8行少一个冒号;
有了第三行代码,编译后就会警告qingshan.c文件的第6行少一个冒号;
三,#pragma使用分析
-
#pragma在有些编译器支持,有些编译器不支持。
-
#pragma即使在有些编译器中支持,编译器对它的解释也是不一样的。
-
#pragma有很多不同用法,具体功能取决于后面接的parameter
一般用法:#pragma parameter
1,#pragma message
语法:#pragma message("此处为要输出的内容...")
作用:仅仅代表一条编译消息。
2,#pragma once
作用:保证头文件只编译一次。
条件编译可以被所用的编译器支持。
#pragma once的效率高,但只有部分编译器支持。
问:如何保证头文件重复时,编译高效又能被所有编译器支持呢?
答:两者相结合即可。
//a.h
#ifndef _A_H
#define _A_H
#pragma once
...
#endif
3,pragma pack
不同类型的数据在内存中按照一定的规则排列,而不是一个接一个的排列。
类型排列方式不同,两者占用的内存空间不同
-
为什么要内存对齐?
——CPU取内存是分块读取的,块的大小是:1,2,4,8,16...字节
——某些硬件平台只能从规定的相对地址处读取特定类型数据,否则就会产生硬件异常。
-
#pragma pack 则用于内存对齐。
语句:
#pragma pack(1)
...
#pragma pack()
编译器在默认情况下按照4字节对齐,也就是说当
#pragma pack未写时=#pragma pack(4);
#pragma pack(4)
struct test1
{ //对齐参数 偏移地址 大小
char c1; // 1 0 1
short s; // 2 4 2
char c2; // 1 6 1
int i; // 4 8 4
};
#pragma pack()
大小为12
如果加上#pragam pack(1):
1 0 1
1 1 2
1 3 1
1 4 4
大小则变成8。
注意:结构体总长度最后要验证能被对齐参数整除。
四,#和##操作符使用分析
1,#操作符
作用:在预处理器将宏参数转换为字符串。
语句:
#define A(x) #x
printf("%s\n", A(hello world!));
(最后打印结果:hello world!)
2,##操作符
作用:在预处理器连接两个标识符。只在宏定义中有效。
语法:
#define CONNECT(a, b) a##b
int CONNECT(a, 1); //int a1;