C - 如何创建处理数组中不同数据类型的单个函数

c - how to create a single function that handle different data type in an array

提问人:QC4R 提问时间:11/15/2023 更新时间:11/16/2023 访问量:98

问:

我想创建一个函数,它可以修改静态数组的最后一个元素,但可以处理不同类型的数据(int16_t、uint16_t 和浮点数)

我已经设法使它适用于每种数据,但功能不同。我想设计一个可以处理每个函数的函数

下面是浮点元素的代码片段。

void fifo_datas_update_float(float data_in, float *datas, uint8_t size)
{       
    datas[size-1] = data_in;        //assign new value to last element
}

const uint8_t dtsize = 3;
static float datas_fake[dtsize] = {10,20,30};
float new_value = 40;
fifo_datas_update_float(new_value, datas_fake, dtsize);

任何帮助将不胜感激......

数组 C 函数

评论

1赞 tadman 11/15/2023
除非你有一个,否则这将是男人的味道不好玩union
1赞 Some programmer dude 11/15/2023
不能使用单个函数,但可以使用宏和泛型
0赞 booo 11/16/2023
感谢您的评论。我实际上考虑了另一种解决方案,即使用简单的函数重载,每种类型都有一个定义。我已经尝试过并且效果很好。我不知道这是否是正确的方法......你怎么看?
0赞 ikegami 11/16/2023
C 没有函数重载。这就是上述发挥作用的地方。_Generic
1赞 Some programmer dude 11/16/2023
对于 C++,您没有 ,但您有模板,当然还有重载。请注意,C 和 C++ 是两种截然不同的语言。_Generic

答:

1赞 ikegami 11/15/2023 #1

您可以使用以下方法:

void set( void *a, size_t i, void *val_ptr, size_t ele_size ) {
   char *p = a;
   memcpy( p + ( i * ele_size ), val_ptr, ele_size );
}

set( datas_fake, dtsize-1, &new_value, sizeof( *datas_fake ) );

但这并不能比直接打电话节省任何东西。memcpy

memcpy( datas_fake + dtsize-1, &new_value, sizeof( *datas_fake ) );

评论

0赞 booo 11/16/2023
我在 Debian 上使用 gcc12.2.0 时出现以下错误:错误:从“void*”到“char*”的转换无效 [-fpermissive] 17 |字符 *p = a;
0赞 pmg 11/16/2023
@QC4R尝试#ifdef __cplusplus / #error bad compiler / #endif
0赞 ikegami 11/16/2023
@QC4R 您似乎正在将代码编译为 C++,但问题被标记为 C。
1赞 pmg 11/16/2023 #2

正如some_programmer_dude在评论中所说,您可以使用(自 C 2011 起)如下所示。
请注意,您只能使用 1 个泛型关联,因此我将其中一个参数设为 a (void *)。
_Generic

#include <inttypes.h>
#include <stdio.h>
 
#define update_last(n, X, p) \
        _Generic((X), \
            float *: updatef, \
            default: updatei16, \
            uint16_t *: updateu16 \
        )(n, X, p)
 
// src must have type (int16_t *)
void updatei16(size_t n, int16_t a[static n], void *src) {
    a[n-1] = *(int16_t *)src;
}
 
// src must have type (uint16_t *)
void updateu16(size_t n, uint16_t a[static n], void *src) {
    a[n-1] = *(uint16_t *)src;
}
 
// src must have type (float *)
void updatef(size_t n, float a[static n], void *src) {
    a[n-1] = *(float *)src;
}
 
int main(void) {
    float ff[1] = { 2023 }, fff = 3.1416F;
    uint16_t uu[1] = { 2023 }, uuu = 42;
    int16_t ii[1] = { 2023 }, iii = -1;
 
    printf("%f, %"PRIu16", %"PRId16"\n", ff[0], uu[0], ii[0]);
 
    update_last(1, ff, &fff);
    update_last(1, uu, &uuu);
    update_last(1, ii, &iii);
 
    printf("%f, %"PRIu16", %"PRId16"\n", ff[0], uu[0], ii[0]);
 
    return 0;
}

查看 https://ideone.com/aAqvTU

上面代码的输出是

2023.000000, 2023, 2023
3.141600, 42, -1

评论

0赞 pmg 11/16/2023
顺便说一句:通过添加适当的功能,您可以使用 、 或 或 、 ...update_last()charlong doublestruct whatever
0赞 booo 11/16/2023
谢谢,这正是我想要的。很抱歉让每个人都混淆了 c 和 c++ 混乱
0赞 Harith 11/16/2023 #3

要建立在@pmg的答案之上,您可以使用:

#define gen_update(_suffix, _type) \
    void update_##_suffix(size_t n, _type a[static n], void *src) \
    {   a[n-1] = *(_type *)src; }

gen_update(ld, long double)
gen_update(d, double)
gen_update(f, float)
gen_update(ull, unsigned long long)
gen_update(ll, long long)
gen_update(ul, unsigned long)
gen_update(l, long)
gen_update(u, unsigned)
gen_update(i, int)
... 
// And so on.

以避免重复。