首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

关于高级编译预处理的几种用法

关于高级编译预处理的几种用法

作者:武汉华嵌  技术部

C程序的源代码中可包括各种编译指令,这些指令称为预处理命令。虽然它们实际上不是C语言的一部分,但却扩展了C程序设计的环境。本节将介绍如何应用预处理程序和注释简化程序开发过程,并提高程序的可读性。

一、C宏体中出现的##@##
1、#的功能是将其后面的宏参数进行字符串化操作(Stringfication)
2、##被称为连接符(concatenator),用来将两个Token连接为一个Token。
3、#@的功能是将其后面的宏参数进行字符化。
以下是应用的代码:
#include <stdio.h>
#define Conn(x,y) x##y
#define ToChar(a) #@a
#define ToString(x) #x
int main()
{
      int a = Conn(1,2);
      printf("%d\n", a);
      printf("%c\n", ToChar(4));
      printf(ToString(45678\n));
      return 0;
}
输出结果为:
      12
      4
      45678

以下是UBOOT中的一部分源代码:
#define U_BOOT_CMD(name, maxargs, rep, cmd, usage, help)\
cmd_tbl_t         u_boot_cmd_##name     Struct_Section = {#name, maxargs, rep, cmd, usage}


二、#pragma  pack()的使用:
      在所有的预处理指令中,#pragma 指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作。#pragma指令对每个编译器给出了一个方法,在保持与C和C ++语言完全兼容的情况下,给出主机或操作系统专有的特征。依据定义,编译指示是机器或操作系统专有的,且对于每个编译器都是不同的。
其格式一般为:#pragma para,其中para为参数,下面来看一些常用的参数。
#pragma pack规定的对齐长度,什么是对齐,以及为什么要对齐:现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地址访问,这就需要各类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。对齐的作用和原因:各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出,而如果存放在奇地址开始的地方,就可能会需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该int数据。显然在读取效率上下降很多。这也是空间和时间的博弈。对齐的实现通常,我们写程序的时候,不需要考虑对齐问题。编译器会替我们选择时候目标平台的对齐策略。当然,我们也可以通知给编译器传递预编译指令而改变对指定数据的对齐方法。但是,正因为我们一般不需要关心这个问题,所以因为编辑器对数据存放做了对齐,而我们不了解的话,常常会对一些问题感到迷惑。最常见的就是struct数据结构的sizeof结果,出乎意料。为此,我们需要对对齐算法所了解。
作用:指定结构体、联合以及类成员的packing alignment;
语法:#pragma pack( [show] | [push | pop] [, identifier], n )
#pragma pack(n)来设定变量以n字节对齐方式。n字节对齐就是说变量存放的起始地址的偏移量有两种情况:第一、如果n大于等于该变量所占用的字节数,那么偏移量必须满足默认的对齐方式,第二、如果n小于该变量的类型所占用的字节数,那么偏移量为n的倍数,不用满足默认的对齐方式。结构的总大小也有个约束条件,分下面两种情况:如果n大于所有成员变量类型所占用的字节数,那么结构的总大小必须为占用空间最大的变量占用的空间数的倍数;

  #pragma pack(push) //保存对齐状态

  #pragma pack(2)//设定为2字节对齐

  struct test

  {

     char a;

     int b;

     char c;

  };

#pragma pack(pop)//恢复原先的对齐状态

以上结构体的大小为8,下面分析其存储情况,首先为a分配空间,其偏移量为0,满足我们自己设定的对齐方式(2字节对齐),a大小为1个字节。接着开始为b分配空间,这时其偏移量为2,需要补足1个字节,这样使偏移量满足为n=2的倍数(因为sizeof(int)大于4),b占用4个字节。接着为c分配空间,这时其偏移量为6,满足为2的倍数,c占用1个字节。这时已经为所有成员变量分配了空间,共分配了8个字节,满足为2的倍数。如果把上面的#pragma pack(2)改为#pragma pack(4),那么我们可以得到结构的大小为12。

更多技术文章敬请关注:武汉华嵌-嵌入式培训专家,国内领先的嵌入式服务机构,
http://www.embedhq.org
返回列表