0

假设我们有这样一个函数:

void WonderfulFunction(float a)

很明显,我们可以传递一个inttowonderful_function并且 C 编译器会将这个提升int到一个float.

但是,用户定义的数据类型呢?假设我们使用一条typedef语句为结构提供名称/别名。有什么方法可以定义提升规则、强制转换函数或构造函数,它们会自动将原语转换为 ADT(抽象数据类型)?我意识到这可以在 C++ 中完成,但这需要在 C 中。

我们希望以下代码能够正确编译:

// #include <niffty_promoter_castOperator_thing.h>

struct HappyStruct {
    int happy_int;
}; 
typedef struct HappyStruct HappyStruct;

/* prototype  */
void AnotherWonderfulFunction(HappyStruct hs)    

int main( ) {

    int a = 12345;

    AnotherWonderfulFunction(a); 

   // A caster/promoter included in the
   // header file specifies how to
   // construct a HappyStruct from an int

    return 0;
}  

void AnotherWonderfulFunction(HappyStruct hs)  {

    // do stuff;
}
4

2 回答 2

3

这对于通用选择(YMMV)是“可能的” ;此处描述的内容是您在 C11 中可以获得的最接近的内容。(在 C99、C89 中这根本不可能)。这里,AnotherWonderfulFunction(X)是一个将扩展为的宏(AnotherWonderfulFunction)(AsHappy(X));括号确保宏不会递归扩展。

AsHappy(X)是一个宏,它使用泛型选择从 2 个实用函数中选择一个 -HappyAsIs将 astruct HappyStruct作为参数并按原样返回,而HappyFromInt需要一个int参数,并将其返回包装在 a 中struct。它需要使用实用函数来完成,因为至少 GCC确实检查了其他分支的语言约束,即使它们没有被评估。然后将原始X数据作为参数传递给选定的函数。

#include <stdio.h>

struct HappyStruct {
    int happy_int;
};

void AnotherWonderfulFunction(struct HappyStruct hs) {
    printf("AnotherWonderfulFunction called with hs.happy_int = %d\n", hs.happy_int);
}

struct HappyStruct HappyAsIs(struct HappyStruct s) {
    return s;
}

struct HappyStruct HappyFromInt(int val) {
    return (struct HappyStruct){ val };
}

#define AsHappy(X)                     \
    _Generic((X),                      \
        struct HappyStruct: HappyAsIs, \
        default: HappyFromInt          \
    )(X)

#define AnotherWonderfulFunction(X) (AnotherWonderfulFunction)(AsHappy(X))

int main(void) {
    int a = 42;
    float b = 65536.5;
    struct HappyStruct c = { 123 };

    AnotherWonderfulFunction(a);
    AnotherWonderfulFunction(b);
    AnotherWonderfulFunction(c);
}

并运行程序会产生:

% ./a.out  
AnotherWonderfulFunction called with hs.happy_int = 42
AnotherWonderfulFunction called with hs.happy_int = 65536
AnotherWonderfulFunction called with hs.happy_int = 123

但是,一旦您将指针指向函数,魔法就会消失。

void (*fp)(struct HappyStruct) = AnotherWonderfulFunction;

现在当然fp不能那样工作,因为它不是宏。

...直到你把它变成一个...

#define fp(X) (fp)(AsHappy(X))

所有这些都有些无用,因为 C11 支持复合文字:

AnotherWonderfulFunction((struct HappyStruct){ 42 });

所以它的用途有限 - 大量的黑魔法可以节省一些击键。

于 2017-08-24T20:52:42.263 回答
0

对于您只关心二进制表示的情况(即,不在 int-to-float 的情况下),您可以使用 GCC__attribute__((transparent_union))

于 2017-08-24T21:11:02.790 回答