用C语言创建具有局部变量的类C++模板函数

Creating a C++ Template Like Functions With Local Variables in C

本文关键字:C++ 函数 局部变量 语言 创建      更新时间:2023-10-16

这里有一个谜。

假设我有以下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

如果没有步骤,你可以像这样做一个大的#定义:

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

但是步骤,我有点陷入僵局。对于带有局部变量的C++模板函数,我可以做些什么来获得C中C++模板的相同功能?

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

还要注意,更改#define以包含结果值也不是一个答案,因为这会更改"函数"的签名。

最后,我充分意识到这个谜题可能没有答案。

让您的宏尝试执行模板所做的操作;创建一个内联函数--

#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;
}

怎么样(GCCism):

#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;})

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

请注意,使用内联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在功能上也是如此。