基于C語言實(shí)現(xiàn)泛型編程詳解
心理歷程
寫了一段時(shí)間C++后,真心感覺STL里的容器是個(gè)好東西。一個(gè)容器可以容納任意類型,容器對(duì)外的接口可以操作任意類型的數(shù)據(jù),甚至包括自定義類型的數(shù)據(jù)。這種泛型編程的思想,對(duì)于大型項(xiàng)目而言是非常有好處的。
對(duì)于C而言,想實(shí)現(xiàn)泛型編程并非易事,甚至可以說非常繁瑣,一大堆坑。最主要也沒有現(xiàn)成的輪子可用。當(dāng)然也有一些通過宏實(shí)現(xiàn)了泛型的基礎(chǔ)功能,但是可讀性,可調(diào)試性太差了。
于是就想自己造一個(gè)輪子,實(shí)現(xiàn)基于C對(duì)窗口(順序表)的泛化,目標(biāo)就是實(shí)現(xiàn)不同類型下,規(guī)范接口的一致性。拋磚引玉。
輪子用法
int main( void )
{
// 1、創(chuàng)建一個(gè)窗口,并初始化它,大小為10,類型為double
ValueWindowSquential tmp;
InitValueWindow( &tmp, kValueTypeList[ DOUBLE ], 10 );
double insert_data = 0;
for ( int i = 0; i < tmp.max_size; i++ )
{
// 2、填充這個(gè)窗口,直到窗口填滿
insert_data = i * 10;
if ( kWindowAlreadyFull == ValueWindowFixedInsert( &tmp, &insert_data ) )
{
// 3、打印整個(gè)窗口
printf( "start sort \r\n" );
ShowTheWindow( &tmp );
// 4、整個(gè)窗口排序
ValueWindowSelectSort( &tmp );
// 5、打印排序后的窗口
printf( "end sort \r\n" );
ShowTheWindow( &tmp );
break;
}
}
printf( "test generics \r\n" );
return 0;
}
打印log如下:

這時(shí)想換成創(chuàng)建一個(gè)uint8_t類型的串口,只需要改兩個(gè)地方,這兩個(gè)地方在C++里也避免不了。
int main( void )
{
ValueWindowSquential tmp;
InitValueWindow( &tmp, kValueTypeList[ UINT8 ], 10 );
uint8_t insert_data = 0;
for ( int i = 0; i < tmp.max_size; i++ )
{
insert_data = ( tmp.max_size - i ) * 1;
if ( kWindowAlreadyFull == ValueWindowFixedInsert( &tmp, &insert_data ) )
{
printf( "start sort \r\n" );
ShowTheWindow( &tmp );
ValueWindowSelectSort( &tmp );
printf( "end sort \r\n" );
ShowTheWindow( &tmp );
break;
}
}
printf( "test generics \r\n" );
return 0;
}

大體流程
1.首先初始化一個(gè)空窗口對(duì)象,然后調(diào)用 InitValueWindow 傳入窗口類型,大小,然后初始化它。
2.調(diào)用 ValueWindowFixedInsert 往窗口中插入值,直到窗口滿后反饋狀態(tài)。
3.打印整個(gè)窗口
4.對(duì)窗口排序
5.打印整個(gè)窗口
這里的泛型主要通過查表實(shí)現(xiàn)了,將希望包含的類型加入表中,然后初始化時(shí)傳入其類型和大小。
插入數(shù)據(jù)的時(shí)候,需要保證數(shù)據(jù)類型和窗口類型統(tǒng)一,這算是個(gè)局限性了。
窗口被填充完畢后,會(huì)有反饋窗口狀態(tài),這時(shí)可以調(diào)用 ShowTheWindow 將原始窗口打印。
在調(diào)用 ValueWindowSelectSort 將窗口排序。排序完后再次打印。
可以看到除了初始化的時(shí)候,需要設(shè)定窗口的類型,這和 std::vector< double > 沒什么兩樣,插入數(shù)據(jù)時(shí)需要調(diào)用者確保數(shù)據(jù)類型與窗口統(tǒng)一。
部分源碼
#ifndef __TEST_GENERICS_h
#define __TEST_GENERICS_h
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <stdlib.h>
#include <assert.h>
typedef signed char int8_t;
typedef unsigned char uint8_t;
typedef signed short int16_t;
typedef unsigned short uint16_t;
typedef signed int int32_t;
typedef unsigned int uint32_t;
typedef enum
{
UINT8 = 0,
INT,
FLOAT,
DOUBLE,
ERROR
} TypeName;
const char* kValueTypeList[ ERROR + 1 ] = {
"uint8_t",
"int",
"float",
"double",
"error",
};
TypeName ChangeStringToEnum( const char* tmp );
/**
* @brief 該結(jié)構(gòu)體用于構(gòu)建基礎(chǔ)窗口順序表
* this structure is used to build the basic window sequence table
*/
typedef struct ValueWindowSquential
{
char* type;
void* data;
uint32_t max_size;
uint32_t sequence;
} ValueWindowSquential;
/**
* @brief 初始化窗口,根據(jù)窗口類型,大小,動(dòng)態(tài)分配內(nèi)存給到內(nèi)部緩沖區(qū)
* initialize the window, and dynamically allocate memory to the internal buffer according to the window type and size
*
* @param tmp base structure for Window
* @param type Window type
* @param max_size Window size
*
* @throw assert
*/
void InitValueWindow( ValueWindowSquential* tmp, const char* type, uint32_t max_size );
/**
* @brief 重置或銷毀窗口
* reset or destroy window
*
* @param tmp base structure for Window
*/
void ResetValueWindow( ValueWindowSquential* tmp );
typedef enum
{
kWindowIsNotFull = ( 0 ),
kWindowIsSliding,
kWindowCanNotInsert,
kWindowInputFail,
} SlideWindowState;
/**
* @brief 滑動(dòng)插入數(shù)據(jù)進(jìn)入窗口,先入先出(FIFO模型)
* slide insert data into the window, first in first out (FIFO model)
*
* @param tmp base structure for Window
* @param data insert data
*
* @return SlideWindowState
* kWindowIsNotFull 窗口未填充滿
* kWindowIsSliding 窗口已填充滿并開始滑動(dòng)
*
* kWindowCanNotInsert 窗口不允許插入
* kWindowInputFail 窗口插入數(shù)據(jù)失敗
*/
SlideWindowState ValueWindowSlideInsert( ValueWindowSquential* tmp, void* data );
typedef enum
{
kWindowNotFull = ( 0 ),
kWindowAlreadyFull,
kFixWindowCanNotInsert,
kFixWindowInputFail,
} FixedWindowState;
/**
* @brief 固定窗,往窗口里插入數(shù)據(jù),直到窗口滿了反饋 kWindowAlreadyFull ,否在反饋 kWindowNotFull
* 與滑動(dòng)窗區(qū)別是,固定窗會(huì)采集多組數(shù)據(jù),采集完成才能使用窗口,使用完后從頭重新采集
* 也就是降頻處理數(shù)據(jù),窗口大小20,10ms插入一次,那么降頻到200ms處理一次窗口(數(shù)據(jù))
*
* @param tmp base structure for Window
* @param data insert data
*
* @return FixedWindowState
* kWindowNotFull 窗口未滿
* kWindowAlreadyFull 窗口已滿,可以開始操作
*
* kFixWindowCanNotInsert 窗口不允許插入
* kFixWindowInputFail 窗口插入數(shù)據(jù)失敗
*/
FixedWindowState ValueWindowFixedInsert( ValueWindowSquential* tmp, void* data );
/**
* @brief 遍歷并打印窗口
*
* @param tmp base structure for Window
*/
void ShowTheWindow( ValueWindowSquential* tmp );
#endif // __TEST_GENERICS_h
/**
* @file test_generics.cpp
* @author benzs_war_pig (benzwarpig@outlook.com)
* @brief 構(gòu)建一種基于C的泛型順序表,針對(duì)不同類型的順序表,實(shí)現(xiàn)接口一致化。
* 同時(shí)針對(duì)順序表實(shí)現(xiàn)一些常用操作(排序,濾波,統(tǒng)計(jì)等)
*
* build a generic sequence table based on C, and realize interface consistency
* for different types of sequence tables. At the same time, some common operations (sorting, filtering, statistics, etc.)
* are implemented for the sequence table
*
* @version 1.0
* @date 2022-06-30
*
* @copyright Copyright (c) 2022
*
*/
#include "test_generics.h"
#include "generics_impl.h"
/**
* @brief 將字符串轉(zhuǎn)換成TypeName
* private interface
*
* @param tmp
* @return TypeName
*/
TypeName ChangeStringToEnum( const char* tmp )
{
assert( tmp != NULL );
TypeName return_tmp = ERROR;
if ( strcmp( tmp, kValueTypeList[ UINT8 ] ) == 0 )
{
return_tmp = UINT8;
}
else if ( strcmp( tmp, kValueTypeList[ FLOAT ] ) == 0 )
{
return_tmp = FLOAT;
}
else if ( strcmp( tmp, kValueTypeList[ DOUBLE ] ) == 0 )
{
return_tmp = DOUBLE;
}
else if ( strcmp( tmp, kValueTypeList[ INT ] ) == 0 )
{
return_tmp = INT;
}
else
{
printf( "error char* input !!!" );
assert( 0 );
}
return return_tmp;
}
// 初始化窗口
// Initialize window
void InitValueWindow( ValueWindowSquential* tmp, const char* type, uint32_t max_size )
{
assert( tmp != NULL );
tmp->type = ( char* ) malloc( strlen( type ) * sizeof( char ) );
strncpy( tmp->type, type, strlen( type ) );
tmp->max_size = max_size;
tmp->sequence = 0;
switch ( ChangeStringToEnum( tmp->type ) )
{
case UINT8: {
tmp->data = ( uint8_t* ) malloc( max_size * sizeof( uint8_t ) );
memset( tmp->data, 0, tmp->max_size );
}
break;
case INT: {
tmp->data = ( int* ) malloc( max_size * sizeof( int ) );
memset( tmp->data, 0, tmp->max_size );
}
break;
case FLOAT: {
tmp->data = ( float* ) malloc( max_size * sizeof( float ) );
memset( tmp->data, 0, tmp->max_size );
}
break;
case DOUBLE: {
tmp->data = ( double* ) malloc( max_size * sizeof( double ) );
memset( tmp->data, 0, tmp->max_size );
}
break;
default: {
printf( "error tmp->type input !!!" );
assert( 0 );
}
break;
}
printf( "type is : %s , number is : %d \r\n", tmp->type, max_size );
}
// 重置/銷毀窗口
void ResetValueWindow( ValueWindowSquential* tmp )
{
tmp->sequence = 0;
tmp->max_size = 0;
if ( tmp->data != NULL )
{
free( tmp->data );
tmp->data = NULL;
}
if ( tmp->type != NULL )
{
free( tmp->type );
tmp->type = NULL;
}
}
// 滑動(dòng)往窗口插入數(shù)據(jù)
SlideWindowState ValueWindowSlideInsert( ValueWindowSquential* tmp, void* data )
{
SlideWindowState return_tmp = kWindowIsNotFull;
switch ( ChangeStringToEnum( tmp->type ) )
{
case UINT8: {
uint8_t* tmp_buffer = ( uint8_t* ) tmp->data;
for ( int i = 1; i < tmp->max_size; i++ )
{
tmp_buffer[ i - 1 ] = tmp_buffer[ i ];
}
uint8_t* res = ( uint8_t* ) data;
tmp_buffer[ tmp->max_size - 1 ] = *res;
}
break;
case INT: {
int* tmp_buffer = ( int* ) tmp->data;
for ( int i = 1; i < tmp->max_size; i++ )
{
tmp_buffer[ i - 1 ] = tmp_buffer[ i ];
}
int* res = ( int* ) data;
tmp_buffer[ tmp->max_size - 1 ] = *res;
}
break;
case FLOAT: {
float* tmp_buffer = ( float* ) tmp->data;
for ( int i = 1; i < tmp->max_size; i++ )
{
tmp_buffer[ i - 1 ] = tmp_buffer[ i ];
}
float* res = ( float* ) data;
tmp_buffer[ tmp->max_size - 1 ] = *res;
}
break;
case DOUBLE: {
double* tmp_buffer = ( double* ) tmp->data;
for ( int i = 1; i < tmp->max_size; i++ )
{
tmp_buffer[ i - 1 ] = tmp_buffer[ i ];
}
double* res = ( double* ) data;
tmp_buffer[ tmp->max_size - 1 ] = *res;
}
break;
default: {
printf( "error tmp->type input !!!" );
assert( 0 );
}
break;
}
if ( ++tmp->sequence > tmp->max_size )
{
return_tmp = kWindowIsSliding;
tmp->sequence = tmp->max_size;
}
return return_tmp;
}
// 插入數(shù)據(jù)直到填滿整個(gè)窗口
FixedWindowState ValueWindowFixedInsert( ValueWindowSquential* tmp, void* data )
{
FixedWindowState return_tmp = kWindowNotFull;
switch ( ChangeStringToEnum( tmp->type ) )
{
case UINT8: {
uint8_t* tmp_buffer = ( uint8_t* ) tmp->data;
uint8_t* res = ( uint8_t* ) data;
tmp_buffer[ tmp->sequence ] = *res;
}
break;
case INT: {
int* tmp_buffer = ( int* ) tmp->data;
int* res = ( int* ) data;
tmp_buffer[ tmp->sequence ] = *res;
}
break;
case FLOAT: {
float* tmp_buffer = ( float* ) tmp->data;
float* res = ( float* ) data;
tmp_buffer[ tmp->sequence ] = *res;
}
break;
case DOUBLE: {
double* tmp_buffer = ( double* ) tmp->data;
double* res = ( double* ) data;
tmp_buffer[ tmp->sequence ] = *res;
}
break;
default: {
printf( "error tmp->type input !!!" );
assert( 0 );
}
break;
}
if ( ++tmp->sequence >= tmp->max_size )
{
tmp->sequence = 0;
return_tmp = kWindowAlreadyFull;
}
return return_tmp;
}
// 打印窗口內(nèi)全部值
void ShowTheWindow( ValueWindowSquential* tmp )
{
// printf("current_type:{%d}", ChangeStringToEnum(tmp->type));
switch ( ChangeStringToEnum( tmp->type ) )
{
case UINT8: {
uint8_t* msg = ( uint8_t* ) tmp->data;
for ( int i = 0; i < tmp->max_size; ++i )
{
printf( "i : {%d} , %d \r\n", i, msg[ i ] );
}
}
break;
case INT: {
int* msg = ( int* ) tmp->data;
for ( int i = 0; i < tmp->max_size; ++i )
{
printf( "i : {%d} , %d \r\n", i, msg[ i ] );
}
}
break;
case FLOAT: {
float* msg = ( float* ) tmp->data;
for ( int i = 0; i < tmp->max_size; ++i )
{
printf( "i : {%d} , %f \r\n", i, msg[ i ] );
}
}
break;
case DOUBLE: {
double* msg = ( double* ) tmp->data;
for ( int i = 0; i < tmp->max_size; ++i )
{
printf( "i : {%d} , %f \r\n", i, msg[ i ] );
}
}
break;
default: {
printf( "error tmp->type input !!!" );
assert( 0 );
}
break;
}
}
int main( void )
{
ValueWindowSquential tmp;
InitValueWindow( &tmp, kValueTypeList[ DOUBLE ], 10 );
double insert_data = 0;
for ( int i = 0; i < tmp.max_size; i++ )
{
insert_data = ( tmp.max_size - i ) * 10;
if ( kWindowAlreadyFull == ValueWindowFixedInsert( &tmp, &insert_data ) )
{
printf( "start sort \r\n" );
ShowTheWindow( &tmp );
ValueWindowSelectSort( &tmp );
printf( "end sort \r\n" );
ShowTheWindow( &tmp );
break;
}
}
ResetValueWindow(&tmp);
printf( "test generics \r\n" );
return 0;
}
這是最開始的一版源碼,基本的思路是基于 void* 實(shí)現(xiàn)對(duì)窗口的泛化,把窗口的地址,大小,類型 在初始化時(shí)設(shè)定好,以后所有的結(jié)構(gòu)便基于這些信息,實(shí)現(xiàn)接口一致性。
目前實(shí)現(xiàn)了兩種窗口類型, ValueWindowSlideInsert (滑動(dòng)窗) 和 ValueWindowFixedInsert(固定窗) 。 兩者不同之處只是插入數(shù)據(jù)時(shí)的處理不同。滑動(dòng)窗遵循FIFO模型,即先入先出,窗口狀態(tài)有未滿和開始滑動(dòng),一般開始滑動(dòng)后再對(duì)窗口進(jìn)行操作。
固定窗有未滿和已滿兩種狀態(tài),已滿后會(huì)清空窗口,重新開始填充,這也是兩種常見的窗口模型。
在STL里,當(dāng)有一些底層數(shù)據(jù)結(jié)構(gòu)去存儲(chǔ)數(shù)據(jù)時(shí),要有一些容器的方法(算法),比如排序等,這里先實(shí)現(xiàn)了一些基礎(chǔ)的泛型算法接口:
#ifndef GENERICS_IMPL_H
#define GENERICS_IMPL_H
#include <stdbool.h>
#include "test_generics.h"
/**
* @file generics_impl.h
* @author benzs_war_pig (benzwarpig@outlook.com)
* @brief 該文件實(shí)現(xiàn)了一些操作泛型順序表的算法,如排序,查找,遍歷,判斷變化率等等
*
* this file implements some algorithms for operating generic sequential tables, such as sorting, searching, traversing,
* judging the rate of change, and so on
*
* @version 1.0
* @date 2022-06-30
*
* @copyright Copyright (c) 2022
*
*/
/**
* @brief 交換順序表中兩個(gè)成員的值
*
* @param tmp base structure for Window
* @param i
* @param j
*/
static void swap( ValueWindowSquential* tmp, uint32_t i, uint32_t j )
{
assert( tmp != NULL );
// assert( i > tmp->max_size || j > tmp->max_size );
// assert( i >= tmp->max_size || j >= tmp->max_size );
switch ( ChangeStringToEnum( tmp->type ) )
{
case UINT8: {
uint8_t* tmp_buffer = ( uint8_t* ) tmp->data;
uint8_t res = tmp_buffer[ i ];
tmp_buffer[ i ] = tmp_buffer[ j ];
tmp_buffer[ j ] = res;
}
break;
case INT: {
int* tmp_buffer = ( int* ) tmp->data;
int res = tmp_buffer[ i ];
tmp_buffer[ i ] = tmp_buffer[ j ];
tmp_buffer[ j ] = res;
}
break;
case FLOAT: {
float* tmp_buffer = ( float* ) tmp->data;
float res = tmp_buffer[ i ];
tmp_buffer[ i ] = tmp_buffer[ j ];
tmp_buffer[ j ] = res;
}
break;
case DOUBLE: {
double* tmp_buffer = ( double* ) tmp->data;
double res = tmp_buffer[ i ];
tmp_buffer[ i ] = tmp_buffer[ j ];
tmp_buffer[ j ] = res;
}
break;
default: {
printf( "error tmp->type input !!!" );
assert( 0 );
}
break;
}
}
static inline void ValueWindowBubbleSort( ValueWindowSquential* tmp )
{
switch ( ChangeStringToEnum( tmp->type ) )
{
case UINT8: {
uint8_t* tmp_buffer = ( uint8_t* ) tmp->data;
bool is_end_loop = true;
for ( int i = 0; i < tmp->max_size && is_end_loop; i++ )
{
is_end_loop = false;
for ( int j = tmp->max_size - 1; j >= i; j-- )
{
if ( tmp_buffer[ j - 1 ] > tmp_buffer[ j ] )
{
swap( tmp, j - 1, j );
is_end_loop = true;
}
}
}
}
break;
case INT: {
int* tmp_buffer = ( int* ) tmp->data;
bool is_end_loop = true;
for ( int i = 0; i < tmp->max_size && is_end_loop; i++ )
{
is_end_loop = false;
for ( int j = tmp->max_size - 1; j >= i; j-- )
{
if ( tmp_buffer[ j - 1 ] > tmp_buffer[ j ] )
{
swap( tmp, j - 1, j );
is_end_loop = true;
}
}
}
}
break;
case FLOAT: {
float* tmp_buffer = ( float* ) tmp->data;
bool is_end_loop = true;
for ( int i = 0; i < tmp->max_size && is_end_loop; i++ )
{
is_end_loop = false;
for ( int j = tmp->max_size - 1; j >= i; j-- )
{
if ( tmp_buffer[ j - 1 ] > tmp_buffer[ j ] )
{
swap( tmp, j - 1, j );
is_end_loop = true;
}
}
}
}
break;
case DOUBLE: {
double* tmp_buffer = ( double* ) tmp->data;
bool is_end_loop = true;
for ( int i = 0; i < tmp->max_size && is_end_loop; i++ )
{
is_end_loop = false;
for ( int j = tmp->max_size - 1; j >= i; j-- )
{
if ( tmp_buffer[ j - 1 ] > tmp_buffer[ j ] )
{
swap( tmp, j - 1, j );
is_end_loop = true;
}
}
}
}
break;
default: {
printf( "error tmp->type input !!!" );
assert( 0 );
}
break;
}
}
static inline void ValueWindowSelectSort( ValueWindowSquential* tmp )
{
switch ( ChangeStringToEnum( tmp->type ) )
{
case UINT8: {
uint8_t* tmp_buffer = ( uint8_t* ) tmp->data;
int tmp_data = 0;
for ( int i = 0; i < tmp->max_size; i++ )
{
tmp_data = i;
for ( int j = i; j < tmp->max_size; j++ )
{
if ( tmp_buffer[ tmp_data ] > tmp_buffer[ j ] )
{
tmp_data = j;
}
}
if ( tmp_data != i )
{
swap( tmp, i, tmp_data );
}
}
}
break;
case INT: {
int* tmp_buffer = ( int* ) tmp->data;
int tmp_data = 0;
for ( int i = 0; i < tmp->max_size; i++ )
{
tmp_data = i;
for ( int j = i; j < tmp->max_size; j++ )
{
if ( tmp_buffer[ tmp_data ] > tmp_buffer[ j ] )
{
tmp_data = j;
}
}
if ( tmp_data != i )
{
swap( tmp, i, tmp_data );
}
}
}
break;
case FLOAT: {
float* tmp_buffer = ( float* ) tmp->data;
int tmp_data = 0;
for ( int i = 0; i < tmp->max_size; i++ )
{
tmp_data = i;
for ( int j = i; j < tmp->max_size; j++ )
{
if ( tmp_buffer[ tmp_data ] > tmp_buffer[ j ] )
{
tmp_data = j;
}
}
if ( tmp_data != i )
{
swap( tmp, i, tmp_data );
}
}
}
break;
case DOUBLE: {
double* tmp_buffer = ( double* ) tmp->data;
int tmp_data = 0;
for ( int i = 0; i < tmp->max_size; i++ )
{
tmp_data = i;
for ( int j = i; j < tmp->max_size; j++ )
{
if ( tmp_buffer[ tmp_data ] > tmp_buffer[ j ] )
{
tmp_data = j;
}
}
if ( tmp_data != i )
{
swap( tmp, i, tmp_data );
}
}
}
break;
default: {
printf( "error tmp->type input !!!" );
assert( 0 );
}
break;
}
}
static inline void ValueWindowInsertSort( ValueWindowSquential* tmp )
{
switch ( ChangeStringToEnum( tmp->type ) )
{
case UINT8: {
uint8_t* tmp_buffer = ( uint8_t* ) tmp->data;
uint8_t tmp_data = 0;
int j = 0;
for ( int i = 1; i < tmp->max_size; i++ )
{
if ( tmp_buffer[ i ] < tmp_buffer[ i - 1 ] )
{
tmp_data = tmp_buffer[ i ];
// TAG : 數(shù)據(jù)整體向后遷移,尋找數(shù)值更大的成員
for ( j = i - 1; tmp_buffer[ j ] > tmp_data && j >= 0; j-- )
{
tmp_buffer[ j + 1 ] = tmp_buffer[ j ];
}
tmp_buffer[ j + 1 ] = tmp_data;
}
}
}
break;
case INT: {
int* tmp_buffer = ( int* ) tmp->data;
int tmp_data = 0;
int j = 0;
for ( int i = 1; i < tmp->max_size; i++ )
{
if ( tmp_buffer[ i ] < tmp_buffer[ i - 1 ] )
{
tmp_data = tmp_buffer[ i ];
// TAG : 數(shù)據(jù)整體向后遷移,尋找數(shù)值更大的成員
for ( j = i - 1; tmp_buffer[ j ] > tmp_data && j >= 0; j-- )
{
tmp_buffer[ j + 1 ] = tmp_buffer[ j ];
}
tmp_buffer[ j + 1 ] = tmp_data;
}
}
}
break;
case FLOAT: {
float* tmp_buffer = ( float* ) tmp->data;
float tmp_data = 0;
int j = 0;
for ( int i = 1; i < tmp->max_size; i++ )
{
if ( tmp_buffer[ i ] < tmp_buffer[ i - 1 ] )
{
tmp_data = tmp_buffer[ i ];
// TAG : 數(shù)據(jù)整體向后遷移,尋找數(shù)值更大的成員
for ( j = i - 1; tmp_buffer[ j ] > tmp_data && j >= 0; j-- )
{
tmp_buffer[ j + 1 ] = tmp_buffer[ j ];
}
tmp_buffer[ j + 1 ] = tmp_data;
}
}
}
break;
case DOUBLE: {
double* tmp_buffer = ( double* ) tmp->data;
double tmp_data = 0;
int j = 0;
for ( int i = 1; i < tmp->max_size; i++ )
{
if ( tmp_buffer[ i ] < tmp_buffer[ i - 1 ] )
{
tmp_data = tmp_buffer[ i ];
// TAG : 數(shù)據(jù)整體向后遷移,尋找數(shù)值更大的成員
for ( j = i - 1; tmp_buffer[ j ] > tmp_data && j >= 0; j-- )
{
tmp_buffer[ j + 1 ] = tmp_buffer[ j ];
}
tmp_buffer[ j + 1 ] = tmp_data;
}
}
}
break;
default: {
printf( "error tmp->type input !!!" );
assert( 0 );
}
break;
}
}
#endif // GENERICS_IMPL_H
以上就是基于C語言實(shí)現(xiàn)泛型編程詳解的詳細(xì)內(nèi)容,更多關(guān)于C語言 泛型編程的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C語言數(shù)據(jù)結(jié)構(gòu)之棧和隊(duì)列的實(shí)現(xiàn)及應(yīng)用
棧和隊(duì)列是一種數(shù)據(jù)結(jié)構(gòu),只規(guī)定了性質(zhì),并沒有規(guī)定實(shí)現(xiàn)方式。本文將以順序結(jié)構(gòu)實(shí)現(xiàn)棧,鏈表方式實(shí)現(xiàn)隊(duì)列,感興趣的小伙伴快跟隨小編一起學(xué)習(xí)一下吧2022-08-08
C++編程中使用設(shè)計(jì)模式中的policy策略模式的實(shí)例講解
這篇文章主要介紹了C++編程中使用設(shè)計(jì)模式中的policy策略模式的實(shí)例講解,文章最后對(duì)策略模式的優(yōu)缺點(diǎn)有一個(gè)簡單的總結(jié),需要的朋友可以參考下2016-03-03
C語言輪轉(zhuǎn)數(shù)組的三種實(shí)現(xiàn)
輪轉(zhuǎn)數(shù)組是一種將數(shù)組元素循環(huán)移動(dòng)的處理方式,它通常用于解決一些需要對(duì)固定長度的數(shù)組進(jìn)行循環(huán)滾動(dòng)處理的問題,本文就介紹了C語言輪轉(zhuǎn)數(shù)組的三種實(shí)現(xiàn),感興趣的可以了解一下2023-08-08
C語言數(shù)組應(yīng)用實(shí)現(xiàn)掃雷游戲
這篇文章主要為大家詳細(xì)介紹了C語言數(shù)組應(yīng)用實(shí)現(xiàn)掃雷游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-06-06
C++拷貝構(gòu)造函數(shù)(深拷貝與淺拷貝)詳解
深拷貝和淺拷貝可以簡單理解為:如果一個(gè)類擁有資源,當(dāng)這個(gè)類的對(duì)象發(fā)生復(fù)制過程的時(shí)候,資源重新分配,這個(gè)過程就是深拷貝,反之,沒有重新分配資源,就是淺拷貝2013-09-09
Visual Studio 2019配置OpenCV4.1.1詳細(xì)圖解教程
這篇文章主要介紹了Visual Studio 2019配置OpenCV4.1.1詳細(xì)圖解教程 ,需要的朋友可以參考下2020-02-02

