0

这里有个谜语。

想象一下,我有以下 C++ 函数:

template<uint8_t MASK>
uint8_t Foo(uint8_t val)
{
    uint8_t step = 0;
    uint8_t result = 0;
    if(MASK & 0x01) {result |= (val & 0x01) >> step; ++step;}
    if(MASK & 0x02) {result |= (val & 0x02) >> step; ++step;}
    //...etc...
    if(MASK & 0x80) {result |= (val & 0x80) >> step; ++step;}

    return result;
}

当我这样实例化这个函数时(下面的所有值都只是示例值):

uint8_t someval = Foo<0xAA>(44);

编译器优化了 Foo() 中的 if 语句,因为它在编译时就知道 if() 语句的结果是什么。

这很好,但尝试在 C 中做同样的事情是有问题的,因为创建了局部变量step

如果step不存在,你可以像这样做一个大的#define:

#define Foo(MASK, val) (\
    ((MASK & 0x01) ? (val & 0x01) : 0) | \
    ((MASK & 0x02) ? (val & 0x02) : 0) | \
    ...etc...
    ((MASK & 0x80) ? (val & 0x80) : 0) | \
    )

但是对于step,我有点陷入僵局。我该怎么做才能在 C 中获得与 C++ 模板相同的功能,用于具有局部变量的 C++ 模板函数?

请注意,使用内联 C 函数不是答案,因为编译器在编译时不知道MASK的值,因此所有比较都不会被优化,因此将成为最终编译输出的一部分。

另请注意,更改 #define 以包含结果值也不是答案,因为这会更改“函数的”签名。

最后,我完全清楚这个谜语可能没有答案。

4

3 回答 3

5

让你的宏尝试做模板所做的事情;创建一个内联函数——

#define Foo(MASK, val) inline uint8_t Foo_##MASK(uint8_t val) \
{ \
   uint8_t step = 0; \
    uint8_t result = 0; \
    if(MASK & 0x01) {result |= (val & 0x01) >> step; ++step;} \
    if(MASK & 0x02) {result |= (val & 0x02) >> step; ++step;} \
    //...etc...
    if(MASK & 0x80) {result |= (val & 0x80) >> step; ++step;} \
\
    return result;\
}
于 2012-08-17T19:56:57.187 回答
2

怎么样(GCC主义):

#define Foo(MASK, val) ({ \
    uint8_t step = 0; \
    uint8_t result = 0; \
    if(MASK & 0x01) {result |= (val & 0x01) >> step; ++step;} \
    if(MASK & 0x02) {result |= (val & 0x02) >> step; ++step;} \
    //...etc...
    if(MASK & 0x80) {result |= (val & 0x80) >> step; ++step;} \
    result;})
于 2012-08-17T19:52:14.900 回答
1

你只是在做一个错误的假设

请注意,使用内联 C 函数不是答案,因为编译器在编译时不会知道 MASK 的值,因此所有比较都不会被优化,因此将成为最终编译输出的一部分。

我刚刚测试过,gcc 能够毫无问题地内联所有内容:

static inline
unsigned Foo(unsigned MASK, unsigned char val)
{
    unsigned char step = 0;
    unsigned char result = 0;
    if(MASK & 0x01) {result |= (val & 0x01) >> step; ++step;}
    if(MASK & 0x02) {result |= (val & 0x02) >> step; ++step;}
    //...etc...
    if(MASK & 0x80) {result |= (val & 0x80) >> step; ++step;}

    return result;
}

int main(int argc, char *argv[]) {
  return Foo(0x02, argc);

}

产生以下汇编程序main

main:
.LFB1:
    .cfi_startproc
    andl    $2, %edi
    movzbl  %dil, %eax
    ret
    .cfi_endproc
.LFE1:
    .size   main, .-main

和 clang 在功能上是一样的。

于 2012-08-17T22:04:17.310 回答