宏的几个绝妙用法

1. 二进制形式的图形表现形式
  这个例子摘自《C专家编程》。根据位模式构建图形图标(icon)或者图形(glyph),是一种小型的位模式映射于屏幕产生的图像。一个位代表图像上的一个像素。如果一个位被设置,那么它所代表的像素就是“亮”的。如果一个位被清除,那么它所代表的像素就是“暗”的。所以,一系列的整数值能够用于为图像编码。类似Iconedit这样的工具就是用于绘图的,他们所输出的是一个包含一系列整型数的ASCII文件,可以被一个窗口程序所包含。它所存在的问题是程序中的图标只是一串十六进制数。在C语言中,典型的16X16的黑白图形可能如下:
static unsigned short stopwatch[] = {
0x07C6,/*二进制形式 0000 0111 1100 0110*/
0x1FF7,
0x383B,
0x600C,
0x600C,
0xC006,
0xC006,
0xDF06,
0xC106,
0xC106,
0x610C,
0x610C,
0x3838,
0x1FF0,
0x07C0,
0x0000
};
  正如所看到的那样,这些C语言常量并未有提供有关图形实际模样的任何线索。这里有一个惊人的#define定义的优雅集合,允许程序建立常量使它们看上去像是屏幕上的图形。
#define X )*2+1
#define _ )*2
#define s ((((((((((((((((0 /* For building glyphs 16 bits wide */
  定义了它们之后,只要画所需要的图标或者图形等,程序会自动创建它们的十六进制模式。使用这些宏定义,程序的自描述能力大大加强,上面这个例子可以转变为:
static unsigned short stopwatch[] =
{
s _ _ _ _ _ X X X X X _ _ _ X X _ ,
s _ _ _ X X X X X X X X X _ X X X ,
s _ _ X X X _ _ _ _ _ X X X _ X X ,
s _ X X _ _ _ _ _ _ _ _ _ X X _ _ ,
s _ X X _ _ _ _ _ _ _ _ _ X X _ _ ,
s X X _ _ _ _ _ _ _ _ _ _ _ X X _ ,
s X X _ _ _ _ _ _ _ _ _ _ _ X X _ ,
s X X _ X X X X X _ _ _ _ _ X X _ ,
s X X _ _ _ _ _ X _ _ _ _ _ X X _ ,
s X X _ _ _ _ _ X _ _ _ _ _ X X _ ,
s _ X X _ _ _ _ X _ _ _ _ X X _ _ ,
s _ X X _ _ _ _ X _ _ _ _ X X _ _ ,
s _ _ X X X _ _ _ _ _ X X X _ _ _ ,
s _ _ _ X X X X X X X X X _ _ _ _ ,
s _ _ _ _ _ X X X X X _ _ _ _ _ _ ,
s _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
};
  显然,与前面的代码相比,它的意思更为明显。标准的C语言具有八进制、十进制和十六进制常量,但没有二进制常量,否则的话倒是一种更为简单的绘制图形模式的方法。
  如果抓住书的右上角,并斜这看这一页,可能会猜测这是一个用于流行窗口系统的“cursor busy”小秒表图形。千万不要忘了在绘图结束后清除这些宏定义,否这很可能会给你后面的代码带来不可预测的后果。
 
  同志们可以自己编写程序来测试以下这种转变的过程,下面附录本人的部分测试代码 (编译环境cygwin gcc):
 
#include <stdio.h>
#define X )*2+1
#define _ )*2
#define s ((((((((((((((((0 /* For building glyphs 16 bits wide */
#define TO_STR(s) #s
 
typedef int bool;
static char string[1000]="";
 
static unsigned short stopwatch[] =
{
  0x07C6,/*0:0000 0111 1100 0110 */
  0x1FF7,/*1*/
  0x383B,/*2*/
  0x600C,/*3*/
  0x600C,/*4*/
  0xC006,/*5*/
  0xC006,/*6*/
  0xDF06,/*7*/
  0xC106,/*8*/
  0xC106,/*9*/
  0x610C,/*10*/
  0x610C,/*11*/
  0x3838,/*12*/
  0x1FF0,/*13*/
  0x07C0,/*14*/
  0x0000 /*15*/
};
 
static unsigned short stopwatch2[] =
{
  s _ _ _ _ _ X X X X X _ _ _ X X _ ,/*((((...)*2+1...*/
  s _ _ _ X X X X X X X X X _ X X X ,
  s _ _ X X X _ _ _ _ _ X X X _ X X ,
  s _ X X _ _ _ _ _ _ _ _ _ X X _ _ ,
  s _ X X _ _ _ _ _ _ _ _ _ X X _ _ ,
  s X X _ _ _ _ _ _ _ _ _ _ _ X X _ ,
  s X X _ _ _ _ _ _ _ _ _ _ _ X X _ ,
  s X X _ X X X X X _ _ _ _ _ X X _ ,
  s X X _ _ _ _ _ X _ _ _ _ _ X X _ ,
  s X X _ _ _ _ _ X _ _ _ _ _ X X _ ,
  s _ X X _ _ _ _ X _ _ _ _ X X _ _ ,
  s _ X X _ _ _ _ X _ _ _ _ X X _ _ ,
  s _ _ X X X _ _ _ _ _ X X X _ _ _ ,
  s _ _ _ X X X X X X X X X _ _ _ _ ,
  s _ _ _ _ _ X X X X X _ _ _ _ _ _ ,
  s _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
};
 
int main(int argc, char *argv[])
{
 bool          equal;
 unsigned int  n,number;
 unsigned int  size; 
 char*         pch; 
 
 size   = sizeof(stopwatch);
 number = size/sizeof(stopwatch[0]);
 equal  = memcmp(stopwatch,stopwatch2,size);
 
 
 for(n=0;n<number;n++)
 {/*打印watch和watch2*/
  printf("id %2d: watch 0x%4x,watch2 0x%4x/n",n,/
     stopwatch[n],stopwatch2[n]);  
 }
 
#if 1/*method 1*//*模拟编译时的替换过程和最终显示*/
 { 
  int i=0;
  int n=0;
  int len=0;
  
  pch=(char*)(TO_STR(s _ _ _ _ _ X X X X X _ _ _ X X _));
  
  n=strlen(pch);
 
  for(i=0;i<n;i++)
  {
   switch(pch[i])
   {
    case 's':
     strcat(string,"((((((((((((((((0");
     break;     
    case '_':
     strcat(string,")*2");
     break;    
    case 'X':
     strcat(string,")*2+1"); 
     break; 
    default:break;  
   }
  } 
  printf("%s/n",string); 
 } 
#else/* alternative*/
#endif 
  
 printf("/nanswer %s equal/n",equal?"not":"is");
}
 
最终的输出结果如下:
id  0: watch 0x 7c6,watch2 0x 7c6
id  1: watch 0x1ff7,watch2 0x1ff7
id  2: watch 0x383b,watch2 0x383b
id  3: watch 0x600c,watch2 0x600c
id  4: watch 0x600c,watch2 0x600c
id  5: watch 0xc006,watch2 0xc006
id  6: watch 0xc006,watch2 0xc006
id  7: watch 0xdf06,watch2 0xdf06
id  8: watch 0xc106,watch2 0xc106
id  9: watch 0xc106,watch2 0xc106
id 10: watch 0x610c,watch2 0x610c
id 11: watch 0x610c,watch2 0x610c
id 12: watch 0x3838,watch2 0x3838
id 13: watch 0x1ff0,watch2 0x1ff0
id 14: watch 0x 7c0,watch2 0x 7c0
id 15: watch 0x   0,watch2 0x   0

((((((((((((((((0)*2)*2)*2)*2)*2)*2+1)*2+1)*2+1)*2+1)*2+1)*2)*2)*2)*2+1)*2+1)*2
 
answer is equal
 
2. 宏在跨平台环境中的运用
罗列下列代码的目的在于:
a.NAMEHACK 这个宏定义如何巧妙地融合两种或两种以上处理器,做到跨平台设计。这样可以做到仅仅在宏定义中提到处理器类型,而在其它代码中不必指出处理器类型。
b.巧妙地在接口中使用IN、OUT和INOUT来标识参数功能。
 
 
#include <stdio.h>
 
/*指定处理器为MAPCA处理器*/
#define NAMEHACK(name) mapca_ ## name
#ifndef NAMEHACK
#define NAMEHACK(name) eti_  ## name
#endif
 
#define TRUE    1
#define FALSE   0
 
#define IN              /*用于指示参数为输入参数 */
#define OUT             /*用于指示参数为输出参数 */
#define INOUT           /*用于指示参数为输入且输出参数 */
 
#define SYM_TO_STR(x) (#x)/*将标识符转化为字符串*/
#define IS_MAPCA(name) (strcmp(SYM_TO_STR(name),"mapca")>=0?1:0)    
 
#define MAX_CPU_NUM  (0x10)
typedef void* HANDLE;
 
struct arch_dep_ops {   /*与处理器相关的操作*/
  unsigned long (*get_cpu_type)(HANDLE);
  int           (*unstall_cpu)(HANDLE);
  int           (*flush_dcache)(HANDLE);
};
 
typedef struct NAMEHACK(cpu) {/*CPU数据结构,与处理器相关*/
  unsigned long  cpu_type;
  int      core_running;/*cpu is runing or not*/
  struct   arch_dep_ops *ops;/* Arch-dependent operations */
}arch_dep_cpu;
 
arch_dep_cpu arch_dep_cpus[MAX_CPU_NUM];
 
unsigned long NAMEHACK(get_cpu_type)(OUT HANDLE handle)
{/*获得CPU类型*/
 arch_dep_cpu *cpu;
 unsigned int cpu_type=0;
 cpu=(arch_dep_cpu*)handle;
 
 if(IS_MAPCA(NAMEHACK(get_cpu_type)))
 {
  cpu->cpu_type=0x1<<1;
  printf("cpu belongs to mapca architecture!/n");  
 }
 else
 {
  cpu->cpu_type=0x1<<2;  
  printf("cpu belongs to eti architecture!/n"); 
 }
 
 return cpu->cpu_type;
}
 
int NAMEHACK(unstall_cpu)(IN HANDLE handle)
{/*运行CPU*/
 arch_dep_cpu *cpu;
 
 cpu=(arch_dep_cpu*)handle;
 if(cpu->cpu_type & 0x1<<1)
 {
   printf("mapca cpu is running!/n");
 
  /*make mapca cpu run
  ...
  */
 }
 else
 {
  printf("eti cpu is running!/n");
 
  /*make eti cpu run
  ...
  */
 }
 
 cpu->core_running=TRUE;
 
 return TRUE;
}
 
int NAMEHACK(flush_dcache)(INOUT HANDLE handle)
{
 /*flush data cache*/
}
struct arch_dep_ops NAMEHACK(ops) = {
  NAMEHACK(get_cpu_type),
  NAMEHACK(unstall_cpu),
  NAMEHACK(flush_dcache)
};
 
int main(int argc, char *argv[])
{
 arch_dep_cpu* cpu_specified;
 unsigned char cpu_id_specified=0;
 
 /*运行由用户指定的CPU*/
 cpu_id_specified=1;
 
 cpu_specified=&arch_dep_cpus[cpu_id_specified];
 
 (*NAMEHACK(ops).get_cpu_type)(cpu_specified);
 (*NAMEHACK(ops).unstall_cpu)(cpu_specified);
}
 
-----------------------------------------------------
用cygwin编译器编译运行以上代码得到如下结果:
 
cpu belongs to mapca architecture!
mapca cpu is running! 
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值