首页 > 解决方案 > 有没有办法避免多个类似功能中的代码重复?

问题描述

我正在编写一系列函数,这些函数将嵌入一个几乎实时运行的小型微控制器中,因此每个时钟周期都很重要。功能几乎相同。

我可以看到在不复制大量代码的情况下做到这一点的唯一方法是使用非常丑陋且不赞成在包含文件中声明代码的方法,然后有意包含多次。

以下作品展示了这个概念:

// func.inc

// The absence of an include guard is intentional, as each time this file gets included
// the output will be different

void FUNC(int x)
{
    /* SNIP - lots and lots of code that is duplicated between 
       variant A and B (and more) of the function
    for ( ... 4096 ) 
    {
        for( lots more nested loops)
        {
    */
    // IMPORTANT - I do not want to call functions here as it is
    // in a tight loop withconsecutive memory accesses of 
    // different sizes of strided sparse arrays
#ifdef A
    printf("A %d\n", x);
#endif
#ifdef B
    printf("B %d\n", x);
#endif
    /*
        }
    }
    */
// main.c

#include <stdio.h>

#define FUNC func_A  
#define A
#include "func.inc"
#undef A
#undef FUNC

#define FUNC func_B  
#define B
#include "func.inc"
#undef B
#undef FUNC

#define FUNC func_AB  
#define A
#define B
#include "func.inc"

int main()
{
    func_A(10);
    func_B(20);
    func_AB(30);

    printf("Done\n");

    return 0;
}

我的问题是,虽然这可行,但它看起来很可怕,并且可能会让其他试图理解它的人感到非常困惑。在这种情况下,使用指向函数的指针效率太低,不能成为可行的选择。

是否有任何人都可以建议的解决方案,而无需简单地复制同一功能的几个略有不同的版本?

标签: cembeddedcode-duplication

解决方案


这里并不清楚什么是伪代码和真实代码,但总体而言,您不应该将++#define用于不同的代码生成目的。(尽管作为最后的手段,您可以使用“X 宏”来做到这一点。这不是一个理想的解决方案,但比这更好。)#undef#include

“重要 - 我不想在这里调用函数”的解决方案是调用函数。

函数内联已经存在了大约 30 年,而 20 年前,C 得到了明确的语言支持。现在编译器比程序员更能确定内联的内容。我将做一个明确的例子inline来证明调用函数不会影响性能,如果正确完成。

使用传统的 C,你会做这样的事情:

#include <stdio.h>

static inline void SNIP (void)
{
  puts(__func__);
}

static inline void A_stuff (int val)
{
  printf("%s %d\n", __func__, val);
}

static inline void B_stuff (int val)
{
  printf("%s %d\n", __func__, val);
}

typedef enum { A=1, B=2 } AB_t;

void func(AB_t ab, int val)
{
  SNIP();

  if(ab & A)
    A_stuff(val);
  if(ab & B)
    B_stuff(val);
}

int main()
{
  func(A, 10);
  func(B, 20);
  func(A|B, 30);

  printf("Done\n");
  return 0;
}

这是理智的解决方案。在生成的机器代码中实际调用的唯一函数是func打印函数。

或者,您也可以使用“X 宏”进行代码生成 - 这些仅出于避免代码重复的目的而存在,以牺牲可读性为代价。在这里不会真的推荐它,但我会包括一个完整的例子:

#include <stdio.h>

#define FUNC_LIST \
  X(A,  10)       \
  X(B,  20)       \
  X(AB, 30)       \


static inline void SNIP (void)
{
  puts(__func__);
}

static inline void A_stuff (int val)
{
  printf("%s %d\n", __func__, val);
}

static inline void B_stuff (int val)
{
  printf("%s %d\n", __func__, val);
}

static inline void AB_stuff (int val)
{
  A_stuff(val);
  B_stuff(val);
}

#define X(opt, val) void func_##opt (int x) { SNIP(); opt##_stuff(x); }
  FUNC_LIST
#undef X


int main()
{
  #define X(opt, val) func_##opt(val),
    FUNC_LIST
  #undef X

  printf("Done\n");
  return 0;
}

就像原始代码一样,这很不可读,除了“X 宏”是用于避免代码重复的 icky 宏技巧的事实上的标准。

这会像 C++ 模板一样创建多个函数,因此也不理想。


推荐阅读