c语言泛型模板

前言

我们都知道c语言没有泛型,大多数人都是通过void*泛型指针来模拟,这也是我前段时间使用过的方法,但是这个方法无法模拟出真正的类型,你们也看见了我那篇stack强制转换的操作,这个很不方便.

今天我们来用宏模拟类型,创建简单数据结构模板

c语言作用域

实现机制,通过预处理复制一遍代码

由于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就是抽象数据

点击查看stack.h
//
// 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.h

这个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

看一下源码你就明白咋回事了,关于嵌套宏请看我前面的文章
只要宏遇见#或##就停止解析

点击查看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.这个代码还是有点不足

  • 使用模板时不能像c++那样随时随地的定义使用,只有函数体外声明了才可以使用

测试

接下来是完整的测试代码

点击查看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]

你可能感兴趣的:(C语言)