简单宏定义实现

简单宏定义 - 方式一

这种方式将主要实现部分放在一个宏定义中,利用字符替换的方式实现不同 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_fooprocess_image_barprocess_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 语言中模板的几种实现方式的更多相关文章

  1. spring 整合 mybatis 中数据源的几种配置方式

    因为spring 整合mybatis的过程中, 有好几种整合方式,尤其是数据源那块,经常看到不一样的配置方式,总感觉有点乱,所以今天有空总结下. 一.采用org.mybatis.spring.mapp ...

  2. Django中提供的6种缓存方式

    由于Django是动态网站,所有每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用: 缓存,缓存将一个某个views的返回值保存至内存或者memcache中, ...

  3. 【温故知新】——原生js中常用的四种循环方式

    一.引言 本文主要是利用一个例子,讲一下原生js中常用的四种循环方式的使用与区别: 实现效果: 在网页中弹出框输入0   网页输出“欢迎下次光临” 在网页中弹出框输入1   网页输出“查询中……” 在 ...

  4. Springboot中IDE支持两种打包方式,即jar包和war包

    Springboot中IDE支持两种打包方式,即jar包和war包 打包之前修改pom.xml中的packaging节点,改为jar或者war    在项目的根目录执行maven 命令clean pa ...

  5. JAVA高级架构师基础功:Spring中AOP的两种代理方式:动态代理和CGLIB详解

    在spring框架中使用了两种代理方式: 1.JDK自带的动态代理. 2.Spring框架自己提供的CGLIB的方式. 这两种也是Spring框架核心AOP的基础. 在详细讲解上述提到的动态代理和CG ...

  6. C语言中这么骚的退出程序的方式你知道几个?

    C语言中这么骚的退出程序的方式你知道几个? 前言 在本篇文章当中主要给大家介绍C语言当中一些不常用的特性,比如在main函数之前和之后设置我们想要执行的函数,以及各种花式退出程序的方式. main函数 ...

  7. Vue中常用的几种传值方式

    Vue中常用的几种传值方式 1. 父传子 父传子的实现方式就是通过props属性,子组件通过props属性接收从父组件传过来的值,而父组件传值的时候使用 v-bind 将子组件中预留的变量名绑定为da ...

  8. DDD:四色原型中Role的 “六” 种实现方式和PHP的Swoole扩展

    目录 背景六种实现方式第一种:未显式体现角色的模式.第二种:使用“显式接口”显式体现角色的模式.第三种:使用“扩张方法”显式体现角色的模式.第四种:使用“领域服务”显式体现角色的模式.第五种:使用“包 ...

  9. Golang中map的三种声明方式和简单实现增删改查

    package main import ( "fmt" ) func main() { test3 := map[string]string{ "one": & ...

随机推荐

  1. 流API--缩减操作

    在Stream流操作中,比如说min(),max(),count()方法,这几个操作都会将一个流缩减成一个值,流API将这些操作称为特例缩减.另外,流API同时泛华了缩减这种概念,提供了reduce( ...

  2. Not Found The requested URL / was not found on this server.

    http://www.wanysys.cc/coding/php/800.html 今天在做本地PHP项目的时候,想把之前wampserver的本地虚拟服务器环境访问方式改为本地localhost访问 ...

  3. python--批量下载豆瓣图片之升级版本

    周末下雨没法出门,刷刷豆瓣看看妹子,本想拿以前脚本下载点图片,结果发现运行失败,之前版本为<python--批量下载豆瓣图片>,报错HTTP Error 403: Forbidden,网上 ...

  4. vue调试神器vue-devtools安装

    vue-devtools安装 vue-devtools是一款用来调试Vue应用的Chrome插件,可极大提高开发者调试项目效率,接着我们说一下如何下载安装这个插件; 一. 从chrome商店直接下载安 ...

  5. linux僵尸进程

    什么是僵尸进程?    在UNIX 系统中,一个进程结束了,但是他的父进程没有等待(调用wait / waitpid)他, 那么他将变成一个僵尸进程.  在fork()/execve()过程中,假设子 ...

  6. word文字覆盖问题

    我们在编写word文档时,偶尔会遇到这个问题: 在一个段落中的某个位置修改文字时,直接就把后面的字体给覆盖了,导致后面的句子也不完整了. 解决经过: 之前遇到这种情况,非常恼火,直接新建一个word文 ...

  7. HTML中的表单

    1.HTML中表单元素的基本概念 HTML表单是HTML元素中较为复杂的部分,表单往往和脚本,动态页面,数据处理等功能相结合,因此是制作动态网站很重要的内容. 表单一般用来收集用户的输入信息 2.表单 ...

  8. 浅谈OSI七层模型及ICP/IP四层模型

    1.OSI七层模型的概念 在网络历史的早期,国际标准化组织(ISO)和国际电报电话咨询委员会(CCITT)共同出版了开放系统互联的七层参考模型. 一台计算机操作系统中的网络过程包括从应用请求(在协议栈 ...

  9. Yii框架里用grid.CGridView调用pager扩展不显示最后一页按钮的解决

    有如下一例,调用zii.widgets.grid.CGridView显示Blog信息,代码如下: $this->widget('zii.widgets.grid.CGridView', arra ...

  10. 洛谷 P3711 仓鼠的数学题 [伯努利数 fft]

    P3711 仓鼠的数学题 题意: \[ S_m(x) = \sum_{k=0}^x k^m, 0^0=1\quad 求 \sum_{m=0}^n S_m(x)a_m \] 的答案多项式\(\sum_{ ...