c语言奇淫技巧之模板类型

何为奇淫技巧?

百科解释:指过于奇巧,让人着迷,却又无益的技艺与制品。

c语言奇淫技巧是指,利用c语言的一些细小的语法特性,来实现一些令人着迷的、眼花缭乱的、看似语言本身不支持的功能。比如:实现c语言封装、继承、多态、lambda表达式、动态包含等。在开发中巧妙运用这些技巧,会让你的程序组织起来更加合理。过于玩弄这些技巧则会令你舍本逐末、忽略了项目中其他更重要的事情。

研究奇淫技巧,是一个充满趣味的过程,也是不断深入语言的过程。通过理解这些奇淫技巧,你会发现你曾经理解的一些基本的语言概念其实并不是真的理解。

c语言实现模板类型的原理

我们通常用的c语言语法,是c语言标准规定的语法。然而不同的c编译器在实现标准语法的同时,可能会扩展一些其他的特定语法。这些语法一般都是用在底层的一些库、工具中,如果你经常阅读c语言库,一定能发现它们的踪影。
c语言实现模板类型,是基于gcc的一个扩展。而检查你当前的c编译器是否支持这个扩展,其实很简单。

运行下面的程序,输出1则证明你的编译器支持,如果报错则不支持。

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>

int main(){

int a = ({1;});

printf("%d\n",a);

return 0;
}

实现模板类型

为了便于大家理解,这里采用递进的方式,渐进式修改代码,方便大家明白。

块级作用域

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>

int main(){

({
char* s = "hello";
printf("%s\n",s);
});

return 0;
}

上面的运行后输出hello,说明 ({});可以作为一个块级作用域,里面可以运行代码片段。

返回值

令人惊异的是,这个块级作用域还能对外返回一个值。当然,返回的方式不是return,而是直接写返回值,并带上一个分号。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>

int main(){

int a = ({
char* s = "hello";
printf("%s\n",s);
10;
});

printf("%d\n",a);

return 0;
}

typeof关键字

学过c语言的你一定还记得typeof这么一个关键字,包括我在内,几乎所有人在初学c语言的时候都对这个关键字不怎么注意,觉得是一个很鸡肋的关键字。其实不然,正是这个关键字,才让我们c语言实现模板类型称为可能。

typeof关键字用法如下:

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>

int main(){

int a = 1;

typeof(a) b = 2;

return 0;
}

上面的代码简要的回顾了typeof关键字的用法,它可以根据一个变量的类型去定义另一个变量。

typeof结合gcc扩展1

当typeof关键字与({})语法结合起来,会有意想不到的事情发生:

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>

int main(){

typeof(({
int a;
a;
})) b;

return 0;
}

上面的代码利用typeof和({})语法定义了一个变量b,int类型。还没发现猫腻?别急,我们接着来。

typeof结合gcc扩展2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>

int main(){

typeof(({
typedef struct{
int a;
}TT;
TT TV;
TV;
})) b;

b.a = 10;

printf("%d\n",b.a);

return 0;
}

上面的代码利用typeof和({})语法定义了一个变量b,b是一个结构体类型,结构体包含一个int类型成员。如果现在你一经发现了什么,恭喜你已经掌握了其奥妙所在。如果还没发现,那么继续看下去会令你豁然开朗。

宏定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>

#define Template(T,body) typeof(({ \
typedef struct body _TYPE; \
_TYPE _tmp; \
_tmp; \
}))

#define Data(T) Template(T,{ \
T data; \
})

int main(){

Data(int) data1 = {1};
Data(char*) data2 = {"zhangsan"};
Data(double) data3;

data3.data = 10.23;


return 0;
}

怎么样,是不是很神奇。

模板类型库

到这里,我们就可以写一个模板类型的头文件了,用到模板类型的地方只需要包含这个头文件就可以了。

type.h

 #ifndef _TYPE_H_H_
#define _TYPE_H_H_

#include "lambda.h"

#define Bool short
#define TRUE 1
#define FALSE 0

#define Int int
#define String char*

//-------------------------------------------------
#define IntConsumer Consumer(int)

//-------------------------------------------------
#define IntBiConsumer BiConsumer(int,int)

//-------------------------------------------------
#define IntTiConsumer TiConsumer(int,int,int)

//-------------------------------------------------
#define IntSupplier Supplier(int)
#define StringSupplier Supplier(String)

//-------------------------------------------------
#define IntFunction(rt) Function(rt,int)

//-------------------------------------------------
#define ToIntFunction(t) Function(int,t)

//-------------------------------------------------
#define IntBiFunction(rt) BiFunction(rt,int,int)

//-------------------------------------------------
#define ToIntBiFunction(t1,t2) BiFunction(int,t1,t2)

//-------------------------------------------------
#define IntTiFunction(rt) TiFunction(rt,int,int,int)

//-------------------------------------------------
#define ToIntTiFunction(t1,t2,t3) TiFunction(int,t1,t2,t3)

//-------------------------------------------------
#define IntUnaryOperator UnaryOperator(int)

//-------------------------------------------------
#define IntBinaryOperator BinaryOperator(int)

//-------------------------------------------------
#define Comparator(t) BiFunction(int,t,t)

//-------------------------------------------------
#define Not(t) Function(BOOL,t)

//-------------------------------------------------
#define And(t) BiFunction(BOOL,t,t)

//-------------------------------------------------
#define Or(t) BiFunction(BOOL,t,t)

//-------------------------------------------------
#define Equal(t) BiFunction(BOOL,t,t)

//-------------------------------------------------
#define Test(t) Function(BOOL,t)


#define Template(T,body) typeof(({ \
    typedef struct body _TYPE; \ 
    _TYPE _tmp; \
    _tmp; \
}))

#define BiTemplate(T1,T2,body) typeof(({ \
    typedef struct body _TYPE; \ 
    _TYPE _tmp; \
    _tmp; \
}))

#define TiTemplate(T1,T2,T3,body) typeof(({ \
    typedef struct body _TYPE; \ 
    _TYPE _tmp; \
    _tmp; \
}))

#define Data(T) Template(T,{ \
    T data; \
})

#endif

上面的库文件中定义了Template、BiTemplate、TiTemplate三个宏,分别对应1、2、3个模板参数基本上可以应付绝大多数情况。如果不够,可自行添加。

你的鼓励,是我前进的动力!