C泛型参数转化为函数指针

标签 c function pointers function-pointers gcc-warning

在 C(不是 C++)中是否可能有一个函数指针,它采用通用值(不是指针),并设置了 -pedantic 和 -wall -werror 标志。

注意:我无法更改参数类型。代码必须支持 uint8_t、uint16_t 等类型作为参数

目标:用代码解决问题。

问题

有没有办法将 uint8_t(和/或 uint16_t)参数类型转换为 void*(Approach1)? 专门用于将非指针类型值传递给 void* 值。

有没有一种方法可以设置适用于所有不同值的通用类型(方法 2)?

最后的手段 有没有办法在代码中设置特定的编译器异常?( this question has been answer )

方法 1(导致从 uint8_t 到 void* 的无效转换)

typedef struct
{
    void (*set_func)(void*);
} SetFunction;

void setValue(uint8_t byteValue)//Not a pointer parameter
{
   byteValue++;
}

void setShortValue(uint16_t byteValue)//Not a pointer parameter
{
   byteValue++;
}

int main()
{
    uint8_t a = 123;
    uint16_t b = 321;
    SetFunction pointerFuncion;
    SetFunction pointerFuncionShort;

    //Typecast the setValue to appease compiler warning
    pointerFunction.set_func = (void(*)(void*))&setValue;
    pointerFuncionShort.set_func = (void(*)(void*))&setShortValue;


    //use the function pointer with non-pointer parameter
    // Compile ERROR thrown invalid conversion from uint8_t to void*
    pointerFunction.set_func(a);
    pointerFuncionShort.set_func(b);
}

方法二(参数过多编译错误)

 typedef struct
{
    void (*set_func)();//Blank parameter to allow multiple args
} SetFunction;

void setValue(uint8_t byteValue)//Not a pointer parameter
{
   byteValue++;
}

void setShortValue(uint16_t byteValue)//Not a pointer parameter
{
   byteValue++;
}

int main()
{
    uint8_t a = 123;
    uint16_t b = 321;

    SetFunction pointerFuncion;
    SetFunction pointerFuncionShort;

    //Typecast the setValue to appease compiler warning
    pointerFunction.set_func = (void(*)())&setValue;
    pointerFuncionShort.set_func = (void(*)())&setShortValue;

    //use the function pointer with non-pointer parameter
    pointerFunction.set_func(a);// Compile ERROR thrown "Too many Args"
    pointerFuncionShort.set_func(b);// Compile ERROR thrown "Too many Args"
}

更新

使问题更加清晰。 我有 100 个带有 1 个参数的函数。 函数的1个参数是不同的类型。 我不能更改任何函数,但我希望有 1 个函数指针类型(或更多基于类型)到任何函数。 我可以更改与函数指针关联的任何类型和函数指针的类型,但不能更改它指向的内容。

最佳答案

不,不是。

简单的回答:被调用的函数甚至不知道如何获取参数。

详情:函数代码在调用(执行)的时候就已经固定了。因此它包含访问参数的代码,这取决于 arguemtn 的类型(例如,对于 uint32_t,需要 32 位加载/存储,对于 uint8_t,需要 8 位加载/存储)。因此它甚至无法正确处理取值。 与 C++ 和 Python 等高级语言不同,C 没有内置运行时类型识别的概念。

但是,您可以将 union 传递给函数并分别处理函数中的每个变体。这将生成所有可能的访问。但是,您必须指定要传递的实际类型。这通常由指定实际类型 的第二个参数完成。 该 union 也可以是由类型标识符和实际值组成的结构。但这只是一个信封,一切仍然是明确的。

typedef union {
    int i;
    float f;
} MyValue;

typedef enum {
    MY_VALUE_int,
    MY_VALUE_float
} MyValueType;

void func(MyValueType type, MyValue value)
{
    switch ( type ) {
        ...
    }
}

int main(void)
{
    func(MY_VALUE_int, (MyValueType){ .i=1 });
}

复合文字 参数仅适用于常量,否则您必须先将值分配给一个 union (或只使用该 union )。 gcc 有一个扩展来避免这种情况,所以你可以有一个接受这样一个 union 的函数,但是调用者可以使用一个简单的转换,而不是一个复合文字。这也适用于变量:

    func(MY_VALUE_float, (MyValueType)1.0);

另一种方法是传递 const void * 并进行内部转换。然而,这比 union 方法的风险更大。

所有方法都需要显式传递实际类型(例如使用枚举)。

C11 允许创建一个宏来计算不同的表达式,根据参数的类型使用新的 _Generic构造。这样就可以模拟原来的方法(使用gcc扩展,正常的方法是可能的,但更复杂):

// use the code of the first block here

#define func_generic(val) _Generic((val), \
    int : func(MY_VALUE_int, (MyValueType)(val)), \
    int : func(MY_VALUE_int, (MyValueType)(val)) )

// and call like:
func_generic(1);
func_generic(1.0);

但是,请注意 _Generic 的限制:类型选择器不允许有两种兼容类型(即 const intint但是,对于 uint16_t 和 uint32_t 这两个都不允许。

请注意,gcc(您显然使用)支持使用 -std=c11std=gnu11 的 C11。后者还支持 GNU 扩展。

关于C泛型参数转化为函数指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30534111/

相关文章:

reactjs - 我的 React 应用程序的 Firebase 功能无法正常工作

css - @function 中 SCSS 中的嵌套列表

c - 访问结构中指针(变量)结构的成员

c - 关于 C 中数组和普通值的指针用法

c - 指针初始化。它是如何工作的?

c - 在 C 中,如果 foo 的返回类型为 void,表达式 foo() 是否可以用作空表达式?

c - 我该如何解释 << 和 |在C中

c - 在嵌入式 C 中处理小数

c++ - 函数成员指针

c++ - (指针)在降低测试分数后计算平均函数的问题