本文共 6202 字,大约阅读时间需要 20 分钟。
这个例子摘自《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):
#define X )*2+1
#define _ )*2
#define s ((((((((((((((((0 /* For building glyphs 16 bits wide */
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
罗列下列代码的目的在于:
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!
转载地址:http://efedi.baihongyu.com/