我们都知道c语言没有泛型,大多数人都是通过
void*
泛型指针来模拟,这也是我前段时间使用过的方法,但是这个方法无法模拟出真正的类型,你们也看见了我那篇stack强制转换的操作,这个很不方便.
今天我们来用宏模拟类型,创建简单数据结构模板
实现机制,通过预处理复制一遍代码
由于c语言没有独自的空间,我们只能用不同的命名来确定不同作用域
下面创建通用模板源码template.h
// Created by xunanmu on 2020/1/21.
//
#ifndef TEMPLATE
#error No define "TEMPLATE"m
#else
#define ___(type,T) T##_##type
#define __(type,T) ___(type,T)
#define _(type) __(type,TEMPLATE)
#define $(funcname) __(funcname,functype)
#define init(x) __(init,x)()
#endif //TEMPLATE_TEMPLATE_H
这个嵌套宏如果看不懂先不要管,咱们等下再来分析
下面写一个简单的stack数据结构
定义的模板宏TEMPLATE就是抽象数据
//
// Created by xunanmu on 2020/1/21.
//
#include "template.h"
#define functype _(stack)
#define stack(x) x##_##stack
typedef struct _(stack) _(stack);
struct _(stack){
int top;
TEMPLATE data[10];
TEMPLATE (*pop)(_(stack)*s);
int (*empty)(_(stack) *s);
int (*push)(_(stack) *s,TEMPLATE data);
};
int $(empty)(_(stack) *s)
{
return s->top;
}
TEMPLATE $(pop)(_(stack) *s)
{
return s->data[--s->top];
}
int $(push)(_(stack) *s,TEMPLATE data)
{
if(s->top>9)
return 0;
s->data[s->top++]=data;
return 1;
}
_(stack) $(init)()
{
_(stack) s;
s.top=0;
s.empty=$(empty);
s.pop=$(pop);
s.push=$(push);
return s;
}
#undef TEMPLATE
这个stack我写的比较简单你们下去后可以把他改的更好一点
1.利用嵌套宏来替换名字和类型
这玩意说不清楚咱们写个test.c
测试一下
#define TEMPLATE char
#include "stack.h"
#define TEMPLATE int
#include "stack.h"
typedef struct student{
char name[10];
int age;
}student;
#define TEMPLATE student
#include "stack.h"
输入预处理命令行
gcc -E test.c -o test.i
看一下源码你就明白咋回事了,关于嵌套宏请看我前面的文章
只要宏遇见#或##就停止解析
# 1 "test.c"
# 1 ""
# 1 ""
# 1 "test.c"
# 1 "stack.h" 1
# 1 "template.h" 1
# 5 "stack.h" 2
typedef struct char_stack char_stack;
struct char_stack{
int top;
char data[10];
char (*pop)(char_stack*s);
int (*empty)(char_stack *s);
int (*push)(char_stack *s,char data);
};
int char_stack_empty(char_stack *s)
{
return s->top;
}
char char_stack_pop(char_stack *s)
{
return s->data[--s->top];
}
int char_stack_push(char_stack *s,char data)
{
if(s->top>9)
return 0;
s->data[s->top++]=data;
return 1;
}
char_stack char_stack_init()
{
char_stack s;
s.top=0;
s.empty=char_stack_empty;
s.pop=char_stack_pop;
s.push=char_stack_push;
return s;
}
# 3 "test.c" 2
# 1 "stack.h" 1
# 1 "template.h" 1
# 5 "stack.h" 2
typedef struct int_stack int_stack;
struct int_stack{
int top;
int data[10];
int (*pop)(int_stack*s);
int (*empty)(int_stack *s);
int (*push)(int_stack *s,int data);
};
int int_stack_empty(int_stack *s)
{
return s->top;
}
int int_stack_pop(int_stack *s)
{
return s->data[--s->top];
}
int int_stack_push(int_stack *s,int data)
{
if(s->top>9)
return 0;
s->data[s->top++]=data;
return 1;
}
int_stack int_stack_init()
{
int_stack s;
s.top=0;
s.empty=int_stack_empty;
s.pop=int_stack_pop;
s.push=int_stack_push;
return s;
}
# 5 "test.c" 2
typedef struct student{
char name[10];
int age;
}student;
# 1 "stack.h" 1
# 1 "template.h" 1
# 5 "stack.h" 2
typedef struct student_stack student_stack;
struct student_stack{
int top;
student data[10];
student (*pop)(student_stack*s);
int (*empty)(student_stack *s);
int (*push)(student_stack *s,student data);
};
int student_stack_empty(student_stack *s)
{
return s->top;
}
student student_stack_pop(student_stack *s)
{
return s->data[--s->top];
}
int student_stack_push(student_stack *s,student data)
{
if(s->top>9)
return 0;
s->data[s->top++]=data;
return 1;
}
student_stack student_stack_init()
{
student_stack s;
s.top=0;
s.empty=student_stack_empty;
s.pop=student_stack_pop;
s.push=student_stack_push;
return s;
}
# 10 "test.c" 2
_(type)
主要确定当前数据类型$(funcname)
主要拼接当前类型名和函数名2.这个代码还是有点不足
接下来是完整的测试代码
点击查看test.c#include
#define TEMPLATE char
#include "stack.h"
#define TEMPLATE int
#include "stack.h"
typedef struct student{
char name[10];
int age;
}student;
#define TEMPLATE student
#include "stack.h"
int main() {
stack(char) s1 = init(stack(char));
stack(int) s2 = init(stack(int));
int i;
char c;
for(c='a';c<'j';c++)
s1.push(&s1,c);
for(i=1;i<10;i++)
s2.push(&s2, i);
while (s1.empty(&s1))
printf("%c ",s1.pop(&s1));
puts("");
while (s2.empty(&s2))
printf("%d ",s2.pop(&s2));
puts("");
stack(student) s3 = init(stack(student));
student student1={"徐南木",18};
student student2={"谭小强",20};
s3.push(&s3,student1);
s3.push(&s3,student2);
while (s3.empty(&s3))
printf("[%s,%d]\n",s3.pop(&s3).name,s3.pop(&s3).age);
return 0;
}
测试结果
i h g f e d c b a
9 8 7 6 5 4 3 2 1
[徐南木,20]