C硬核:聊聊预编译指令和宏的应用场景(一)

C语言硬件编程栏目

往期文章:工作数年还是被指针坑了——谈谈C语言指针运算



前言

C语言编程中离不开预编译指令,编译器在预编译阶段,会根据预编译指令对你编写的代码进行处理。
例如,我们在写第一段C程序"HelloWorld"的时候,就用到了#include指令来包含stdio.h这样的头文件了;
而用于定义宏名称的指令#define也属于预编译指令,而且也是用的最多的预编译指令。
下面我们就围绕预编译指令和宏的应用场景,看看哪些是容易被忽略的预编译指令以及重要的应用场景。


一、预编译指令

C中的预编译指令很多,包括#define,#undef,#if,#ifdef,#ifndef,#error,#line, #pragma等等,常用且重要的指令主要是如下这些:

#define指令

编程中最常用的预编译指令要属#define宏定义指令了,其用法及形式如下:

#define NAME stuff

这样在code中其他使用NAME宏名的地方,都会被替换为stuff,这里的stuff可以是各种文本;最常见的常量数值,例如

#define PI 3.1415926

如果要移除一个前面定义的宏,用#undef即可。

#if指令

#if指令用于编译过程的分支判断,和#elif/#else/#endif配合使用。其形式如下:

#if Constant-Expression
  statements
#elif Constant-Expression2
  statements2
#else
  statements3
#endif

因为在Constant-Expression域内可以填写各种表达式的组合,所以该指令往往使用起来灵活多变。例如和defined/!defined配合使用,从而限定某个条件下编译的code,该用法也是常常不被重视但颇有用的一种

#if defined(MACRO_A) && !defined(MACRO_B)
  statements
#endif

这样只有在定义MACRO_A和未定义MACRO_B的时候,才会执行如下的statements。

#ifdef指令

#ifdef指令和#if defined指令是等价的,所以常用#ifdef和#ifndef来实现宏定义下或非定义宏的条件下对code的执行,使用起来简单,但是没次只能对一个宏进行判断,不如#if指令灵活。

#include指令

该指令用于包含code中所需要的头文件,需要注意的是,包含的形式有两种:

//first one
#include <Library/file.h>
//second one
#include "file.h"

两者在检索头文件的过程中,是完全不一样的。第一种会按照编译器指定的库文件目录为根,向下检索头文件;而第二种则会按照当前编辑的C文件为根,去检索file.h。因此我们在使用的时候,如果头文件位于当前目录下,使用第2种方式最佳。

#pragma指令

一定注意,该指令名称是#pragma,不是#progma
该指令稍显复杂,用于设定编译器的状态,指示编译器完成特定的动作。经常配合使用的参数包括message,warning和pack。而我们最常用和最重要的,就是和pack的搭配使用了。使用形式如下:

#pragma pack(n)

在默认情况下,对于结构体是按照最节省空间的方式进行对齐的,如下面的TestStruct1按照最大长度的int i进行对齐,c1/s/c2整体拼成一个单元,如表中所示,即按照pack(1)一个字节进行对齐:

struct TestStruct1
{
   char c1;
   short s;
   char c2;
   int i;
};

内存分布表
内存分布表

当然,上述默认的方式不一定适合编程时数据的访问,如果统一按照4个字节int类型进行访问,那么在结构体声明时使用pack(4)即可,那么这里的内存分布会变成:

c1
s
c2
i

取消自行设定的对齐方式,再使用#pragma pack()即可。下次我们以UEFI kernel为模板,再聊聊宏的应用场景~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cerman

你的鼓励是探索和创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值