C 语言中模板的几种实现方式
简单宏定义实现
简单宏定义 - 方式一
这种方式将主要实现部分放在一个宏定义中,利用字符替换的方式实现不同 type 的运算,详细思路见代码:
simple_macro_1.c
#include <stdint.h>
#define INT8 8
#define INT16 16
#define INT32 32
#define DO_MAIN(type) do { \
int i; \
type *p = buf; \
\
for (i = 0; i < len; i++) { \
p[i] *= k; \
} \
} while(0)
void func(void *buf, int len, float k, int request)
{
if (request == INT8) {
DO_MAIN(int8_t);
} else if (request == INT16) {
DO_MAIN(int16_t);
} else if (request == INT32) {
DO_MAIN(int32_t);
}
}
简单宏定义 - 方式二
这种方式直接利用宏定义实现几个同类函数的定义,详见代码:
simple_macro_2.c
#define DECLARE_FUNC(n) \
static void func_##n(int##n##_t *p, int len, float k) \
{ \
int i; \
\
for (i = 0; i < len; i++) \
p[i] *= k; \
}
DECLARE_FUNC(8)
DECLARE_FUNC(16)
DECLARE_FUNC(32)
接下来就可以使用 func_8()、func_16() 和 func_32() 三个函数了。
包装函数实现
这种方式理解起来非常简单,就是简单地利用一个函数将多个同类函数进行统一整合,详见代码:
alternative_function_creator.c
/*************************************
* foo(), bar(), baz() 三个函数为已有函数
**************************************/
static inline int process_image(void *img, int width, int height, const int n)
{
int x, y;
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
if (n == 0) foo(img, x, y);
else if (n == 1) bar(img, x, y);
else baz(img, x, y);
}
}
}
int process_image_foo(void *img, int width, int height)
{
return process_image(img, width, height, 0);
}
int process_image_bar(void *img, int width, int height)
{
return process_image(img, width, height, 1);
}
int process_image_baz(void *img, int width, int height)
{
return process_image(img, width, height, 2);
}
宏定义和包装函数混合使用实现
针对上述方式,process_image_foo、process_image_bar 和 process_image_baz 三个函数可以利用宏定义简化书写,如下:
mix_macros_functions.c
static inline int process_image(void *img, int width, int height, const int n)
{
int x, y;
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
if (n == 0) foo(img, x, y);
else if (n == 1) bar(img, x, y);
else baz(img, x, y);
}
}
}
#define DECLARE_PROCESS_IMAGE_FUNC(name, n) \
int process_image_##name(void *img, int width, int height) \
{ \
return process_image(img, width, height, n); \
}
DECLARE_PROCESS_IMAGE_FUNC(foo, 0)
DECLARE_PROCESS_IMAGE_FUNC(bar, 1)
DECLARE_PROCESS_IMAGE_FUNC(baz, 2)
这样就可以实现上一种方式同样的效果
外部文件实现
我们还可以用单独的源文件和头文件来实现模板函数,像这样:
extermal_file.c
#if defined(TEMPLATE_U16)
# define RENAME(N) N ## _u16
# define TYPE uint16_t
# define SUM_TYPE uint32_t
#elif defined(TEMPLATE_U32)
# define RENAME(N) N ## _u32
# define TYPE uint32_t
# define SUM_TYPE uint64_t
#elif defined(TEMPLATE_FLT)
# define RENAME(N) N ## _flt
# define TYPE float
# define SUM_TYPE float
#elif defined(TEMPLATE_DBL)
# define RENAME(N) N ## _dbl
# define TYPE double
# define SUM_TYPE double
#endif
TYPE RENAME(func)(const TYPE *p, int n)
{
int i;
SUM_TYPE sum = 0;
for (i = 0; i < 1<<n; i++)
sum += p[i];
return sum;
}
#undef RENAME
#undef TYPE
#undef SUM_TYPE
可以像下面这样使用模板函数:
mian.c
#include <stdint.h>
#define TEMPLATE_U16
#include "evil_template.c"
#undef TEMPLATE_U16
#define TEMPLATE_U32
#include "evil_template.c"
#undef TEMPLATE_U32
#define TEMPLATE_FLT
#include "evil_template.c"
#undef TEMPLATE_FLT
#define TEMPLATE_DBL
#include "evil_template.c"
#undef TEMPLATE_DBL
只需要在使用前对相应类型进行宏定义即可,对应的函数分别是 func_u16()、func_u32()、func_flt() 和 func_dbl()。
C 语言中模板的几种实现方式的更多相关文章
- spring 整合 mybatis 中数据源的几种配置方式
因为spring 整合mybatis的过程中, 有好几种整合方式,尤其是数据源那块,经常看到不一样的配置方式,总感觉有点乱,所以今天有空总结下. 一.采用org.mybatis.spring.mapp ...
- Django中提供的6种缓存方式
由于Django是动态网站,所有每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用: 缓存,缓存将一个某个views的返回值保存至内存或者memcache中, ...
- 【温故知新】——原生js中常用的四种循环方式
一.引言 本文主要是利用一个例子,讲一下原生js中常用的四种循环方式的使用与区别: 实现效果: 在网页中弹出框输入0 网页输出“欢迎下次光临” 在网页中弹出框输入1 网页输出“查询中……” 在 ...
- Springboot中IDE支持两种打包方式,即jar包和war包
Springboot中IDE支持两种打包方式,即jar包和war包 打包之前修改pom.xml中的packaging节点,改为jar或者war 在项目的根目录执行maven 命令clean pa ...
- JAVA高级架构师基础功:Spring中AOP的两种代理方式:动态代理和CGLIB详解
在spring框架中使用了两种代理方式: 1.JDK自带的动态代理. 2.Spring框架自己提供的CGLIB的方式. 这两种也是Spring框架核心AOP的基础. 在详细讲解上述提到的动态代理和CG ...
- C语言中这么骚的退出程序的方式你知道几个?
C语言中这么骚的退出程序的方式你知道几个? 前言 在本篇文章当中主要给大家介绍C语言当中一些不常用的特性,比如在main函数之前和之后设置我们想要执行的函数,以及各种花式退出程序的方式. main函数 ...
- Vue中常用的几种传值方式
Vue中常用的几种传值方式 1. 父传子 父传子的实现方式就是通过props属性,子组件通过props属性接收从父组件传过来的值,而父组件传值的时候使用 v-bind 将子组件中预留的变量名绑定为da ...
- DDD:四色原型中Role的 “六” 种实现方式和PHP的Swoole扩展
目录 背景六种实现方式第一种:未显式体现角色的模式.第二种:使用“显式接口”显式体现角色的模式.第三种:使用“扩张方法”显式体现角色的模式.第四种:使用“领域服务”显式体现角色的模式.第五种:使用“包 ...
- Golang中map的三种声明方式和简单实现增删改查
package main import ( "fmt" ) func main() { test3 := map[string]string{ "one": & ...
随机推荐
- Linux Shell 编程语法
原文地址:http://www.cnblogs.com/fhefh/archive/2011/04/13/2014967.html.感谢作者的无私分享 编写代码 在计划好要程序干什么以及如何使用程序的 ...
- Servlet--超链接,表单提交,重定向,转发4种情况的路径
实际编码中我们经常写路径,写路径既可以写相对路径,也可以写绝对路径.我2年以前我就养成了习惯,只要是写路径我从来都是写绝对路径,因为万一将来我们的项目的目录发生变化,原来要是写相对路径的话就会有路径依 ...
- 关于Mysql模糊查询的优化-全文检索和Like的使用
表A:CREATE TABLE `tableA` (`id` int(11) NOT NULL auto_increment,`content` varchar(256) default NULL,P ...
- 怎样共享windows和linux之间的文件
注:本文参考自:https://www.howtogeek.com/176471/how-to-share-files-between-windows-and-linux/,相当于是原文的翻译. 一. ...
- Android图像数据传递到C++的一些坑
最近在做一个Android图象识别的app, 通过相机预览或者是拍照功能获取图像数据,然后将图像数据传递到本地C++的图像识别so库.在这个过程中花的时间最多的就是数据传输问题.谨以此坑,警示未来! ...
- 弥补wxpython无背景图片缺陷
思路: 通过设置Panel的背景样式为wx.BG_STYLE_CUSTOM: self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) 绑定Panel的背景事情: sel ...
- Python之Django rest_Framework(3)
补充: 为什么要前后端分离: a.因为前端它有自己框架,这样它的效率就非常高 b.不做前后端分离,公司如果既有客户端,又有app这种情况下你就的写两遍 django rest ...
- ABP官方文档翻译 3.1 实体
实体 实体类 聚合根类 领域事件 常规接口 审计 软删除 激活/失活实体 实体改变事件 IEntity接口 实体是DDD(领域驱动设计)的核心概念之一.Eric Evans描述它为"An o ...
- HDU [P1533]
二分图带权最小匹配(朴素) 只要换几个不等号的方向就行,不需要变换权值的正负 #include <iostream> #include <cstdio> #include &l ...
- 读书共享 Primer Plus C-part 5
第五章 运算符.表达式和语句 关于+- 的一元运算符和二元运算符的区别 a++:a先创建自身的一个副本,然后a自增1,最后返回副本的值 a+=1: 事实上相当于++a a=a+1: 虽然有点雷同于a+ ...