gpt4 book ai didi

c - 用于处理 C 中异质签名函数的函数指针的模式

转载 作者:太空狗 更新时间:2023-10-29 15:41:53 34 4
gpt4 key购买 nike

所以,我有一大堆函数可以从某种形式的来源读取输入:

ErrCode_t in_func1(t1_t * const data1);
ErrCode_t in_func2(t2_t * const data2);
...

一些触发函数,告诉我是否可以调用上面的函数:

TrCode_t tr_func1();
TrCode_t tr_func2();
...

和相应的函数来写出数据:

void out_func1(t1_t const * const data1, const uint32_t handled_error);
void out_func2(t2_t const * const data2, const uint32_t handled_error);
...

还有一个非常复杂的算法取决于触发函数,它决定我是否可以调用输入函数。 (这是一张简化的图片;每个 I/O 都有一个以上的触发功能和计时器)。

这个算法基本上说:如果触发器说是,则使用指向数据变量的指针调用输入函数,检查错误,进行一些验证,然后将更新变量的指针传递给输出。

 void execute_f1(t1_t * const pData1)
{
if(evalTr(tr_func1()))
{
const ErrCode_t myErr = in_func1(pData1);
const uint32_t myOutErr = evalError(myErr);

out_func1(pData1,myOutErr);
}
}

(而evalTr和evalError应该是正确使用的一些评估函数)

我想将这个算法封装在一个自己的函数中,

 void execute_io(???)

用一些函数指针调用来执行此操作。但是我想不出一个符合标准的模式,没有大量的包装函数。我包装输入函数和输出函数以执行正确的转换,并调整签名,如:

ErrCode_t my_in_func1(void * const pData1)
{
t1_t * const data1 = (t1_t*) pData1;
return in_func1(data1);
}

和输出函数相似:

 void my out_func2(void const * const data2, const uint32_t handled_error) {...}

这样我就有了同质的签名,这样就很容易得到函数指针。但我真的不想包装所有这些功能。有谁知道可以在 execute_io 和周围代码“内部”工作的模式,所以我不必包装所有这些功能?

更新:这里按照 barak manos 的要求进行组合:

系统接口(interface).h

 ErrCode_t in_func1(t1_t * const data1);
/* some 500 more of them */

TrCode_t tr_func1();
/* some 500 more of them */

void out_func1(t1_t const * const data1, const uint32_t handled_error);
/* some 500 more of them */

我的代码.c

 static ErrCode_t my_in_func1(void * const data1)
{
t1_t * const data1 = (t1_t*) pData1;
return in_func1(data1);
}
/* and some 500 more wrappers */

static void my_out_func1(void const * const pData1, const uint32_t handled_error)
{
t1_t const * const data1 = (t1_t) pData1;
out_func1(pData1, handled_error);
return;
}
/* and some 500 more wrappers */

typedef ErrCode_t (*inFuncPtr)(void * const);
typedef void (*outFuncPtr)(void const * const, const uint32_t);
typedef TrCode_t (*trFuncPtr)();

execute_io(inFuncPtr inFunc, outFuncPtr outFunc, trFuncPtr trFunc, void * pData)
{
if(evalTr((*trFunc)()))
{
const ErrCode_t myErr = (*inFunc)(pData);
const uint32_t myOutErr = evalError(myErr);

(*outFunc)(pData,myOutErr);
}
return;
}

void do_all_my_work()
{
{
t1_t data1;
execute_io(&my_in_func1, &my_out_func1, &tr_func1, &data1);
}
{
t2_t data2;
execute_io(&my_in_func2, &my_out_func2, &tr_func2, &data2);
}
/* and some 499 other calls */
}

我想找到另一种模式,它不会强制我包装所有 I/O 函数。 (不,上面的代码肯定不是一个可执行的例子,而只是一个概念)

最佳答案

我写的东西我相信可以满足您的需求。如果我遗漏了什么,请告诉我。我为您提到的各种函数和类型编写了 stub ,以便代码可以编译,但无论您定义的函数中使用的类型或实现如何,它都应该可以工作。基本上它是有效的,因为所有指针都只是给出内存中值地址的整数,只要指针指向足够大的位置以包含所需的值,该内存的内容对于传递指针并不重要。有时会扰乱这个概念的唯一问题是某些编译器要求特定数据类型沿特定字节边界对齐。为了解决这个问题,我们首先注意到这些字节边界都是 2 的幂,并且对齐永远不会超过最大基元的大小,对于 c 当前是 64 位(8 字节)。即使对于非原始类型也是如此,例如。结构/union 。然后我们所要做的就是在需要保存这个类型数据的缓冲区上额外分配 8 个字节的内存,然后在指针上添加一个 0 到 7 之间的值,使其可以被 8 整除,从而消除对齐问题所有支持 64 位指针或更少的机器。

    /*
* Test.c
*
* Created on: May 14, 2015
* Author: tiger
*/
#include <stdio.h>

typedef int ErrCode_t;
typedef int TrCode_t;
typedef unsigned int uint32_t;
typedef unsigned char uint8_t;
typedef unsigned long long int uint64_t;

typedef int t1_t;
typedef short t2_t;
typedef float t3_t;
typedef double t4_t;
typedef long long int t5_t;

#define MAX_DATA_TYPE_SIZE ((uint32_t)64) //or whatever the size is of your largest data type

uint32_t evalTr(TrCode_t code);
uint32_t evalError(ErrCode_t code);

ErrCode_t in_func1(t1_t* const data1);
ErrCode_t in_func2(t2_t* const data2);
ErrCode_t in_func3(t3_t* const data3);
ErrCode_t in_func4(t4_t* const data4);
ErrCode_t in_func5(t5_t* const data5);

TrCode_t tr_func1();
TrCode_t tr_func2();
TrCode_t tr_func3();
TrCode_t tr_func4();
TrCode_t tr_func5();

void out_func1(t1_t const* const data1, const uint32_t handled_error);
void out_func2(t2_t const* const data2, const uint32_t handled_error);
void out_func3(t3_t const* const data3, const uint32_t handled_error);
void out_func4(t4_t const* const data4, const uint32_t handled_error);
void out_func5(t5_t const* const data5, const uint32_t handled_error);

typedef struct
{
TrCode_t (*tr_func)(void);
ErrCode_t (*in_func)(void* const data);
void (*out_func)(const void* const data, const uint32_t handled_error);
}IOSet;

#define FUNCTION_COUNT ((uint32_t)5)
IOSet ioMap[FUNCTION_COUNT] =
{
{.tr_func = (void*)&tr_func1, .in_func = (void*)&in_func1, .out_func = (void*)&out_func1},
{.tr_func = (void*)&tr_func2, .in_func = (void*)&in_func2, .out_func = (void*)&out_func2},
{.tr_func = (void*)&tr_func3, .in_func = (void*)&in_func3, .out_func = (void*)&out_func3},
{.tr_func = (void*)&tr_func4, .in_func = (void*)&in_func4, .out_func = (void*)&out_func4},
{.tr_func = (void*)&tr_func5, .in_func = (void*)&in_func5, .out_func = (void*)&out_func5}
};

void execute_io(IOSet io, void * const pData)
{
if(evalTr(io.tr_func()))
{
const ErrCode_t myErr = io.in_func(pData);
const uint32_t myOutErr = evalError(myErr);

io.out_func(pData,myOutErr);
}
}

void do_all_my_work()
{
uint32_t i;
//allocate a buffer sufficiently large to hold any of the data types on the stack
// + 8 to allow correcting pointer for any alignment issues
uint8_t dataBuffer[MAX_DATA_TYPE_SIZE + 8];
uint64_t dataHandle = (uint64_t)&dataBuffer;
//ensure the dataHandle is divisible by 8 to satisfy all possible alignments
//all 8 byte alignments are also valid 4 byte alignments
//all 4 byte alignments are also valid 2 byte alignments
//all 2 byte alignments are also valid 1 byte alignments

//you can use a smaller type than uint64_t for this computation if your pointers are smaller,
//but this should work for pointers of all sizes up to 64 bits
if((dataHandle % 8) > 0)
{
dataHandle += 8ULL-(dataHandle % 8);
}

for(i = 0; i < FUNCTION_COUNT; i++)
{
execute_io(ioMap[i], (void*)dataHandle);
}
}

uint32_t evalTr(TrCode_t code)
{
static uint32_t result = 0;
result ^= 1;
return result;
}

uint32_t evalError(ErrCode_t code)
{
return 0;
}

ErrCode_t in_func1(t1_t* const data1)
{
*data1 = 1;
return 0;
}

ErrCode_t in_func2(t2_t* const data2)
{
*data2 = 2;
return 0;
}

ErrCode_t in_func3(t3_t* const data3)
{
*data3 = 3;
return 0;
}

ErrCode_t in_func4(t4_t* const data4)
{
*data4 = 4;
return 0;
}

ErrCode_t in_func5(t5_t* const data5)
{
*data5 = 5;
return 0;
}


TrCode_t tr_func1()
{
return 0;
}

TrCode_t tr_func2()
{
return 0;
}

TrCode_t tr_func3()
{
return 0;
}

TrCode_t tr_func4()
{
return 0;
}

TrCode_t tr_func5()
{
return 0;
}


void out_func1(t1_t const* const data1, const uint32_t handled_error)
{
printf("%d\n", *data1);
return;
}

void out_func2(t2_t const* const data2, const uint32_t handled_error)
{
printf("%d\n", *data2);
return;
}

void out_func3(t3_t const* const data3, const uint32_t handled_error)
{
printf("%f\n", *data3);
return;
}

void out_func4(t4_t const* const data4, const uint32_t handled_error)
{
printf("%f\n", *data4);
return;
}

void out_func5(t5_t const* const data5, const uint32_t handled_error)
{
printf("%llu\n", *data5);
return;
}

int main()
{
for(;;)
{
do_all_my_work();
}
return 0;
}

关于c - 用于处理 C 中异质签名函数的函数指针的模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30221981/

34 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com