【问题标题】:Avoid code duplication in read/write functions using preprocessor使用预处理器避免读/写函数中的代码重复
【发布时间】:2013-06-05 09:39:32
【问题描述】:

如果我有一对长函数:

#include <stdio.h>
#include <stdlib.h>

void writeData()
{
    FILE *fp; int someVar1 = 1; int someVar2 = 2; int someVar3 = 3;

    fp = fopen("results.dat", "a");     // open file

    if (fp == NULL) {
        printf("I couldn't open results.dat for appending.\n");
        exit(0);
    }

    fprintf(fp, "%d\n", someVar1);   // write to file
    fprintf(fp, "%d\n", someVar2);   // write to file
    fprintf(fp, "%d\n", someVar3);   // write to file
    fclose(fp);                     // and close
}

void readData()
{
    FILE *fp; int someVar1, someVar2, someVar3;

    fp = fopen("results.dat", "r");     // open file for reading
    if (fp == NULL) {
        printf("I couldn't open results.dat for reading.\n");
        exit(0);
    }

    fscanf(fp, "%d\n", &someVar1);       // read from file
    fscanf(fp, "%d\n", &someVar2);       // read from file
    fscanf(fp, "%d\n", &someVar3);       // read from file

    fclose(fp);     // and close

    printf("someVar: %d %d %d\n", someVar1, someVar2, someVar3);
}

int main(void)
{
    writeData();
    readData();

    return 0;
}

有没有办法可以(ab)使用预处理器来避免重复读写代码?换句话说,有没有办法在write()read()函数中分别生成一对fprintf(fp, "%d\n", someVar)fprintf(fp, "%d\n", someVar)

编辑:这同样适用于分配/释放整个内存负载,例如http://pastebin.com/wdAnHfWx。基本上任何在两个互补但简单的函数之间有大量代码重复的任务。

【问题讨论】:

  • 我不明白你想要这个。
  • 例如如果我想读/写一大堆变量并保留它们的写/读顺序,那么添加 1 行代码(扩展为读/写版本)比添加行要简单一些分别用于读取和写入功能。另一个(更简单的)示例:pastebin.com/wdAnHfWx
  • read() 和 write() 是函数的 terrible 名称,因为它们也是名称 (unix) 系统调用(由 stdio 函数在内部使用)。如果您想保持理智,请避免使用它们。
  • 是的,这是真的,我只是匆忙把这里的示例代码放在一起!

标签: c c-preprocessor


【解决方案1】:

有一种称为 X 宏的技术可能适合您的需求。您可以在 wikipedia (http://en.wikipedia.org/wiki/X_Macro) 中查看其工作原理的基本信息。

按照 wiki 的说明,您可以创建一个 VAR_LIST,然后将此列表扩展为读或写。

#define MY_VAR_LIST(ENTRY)  \
    ENTRY(var1) \
    ENTRY(var2) \
    ENTRY(var3)

#define EXPAND_AS_DEFINITION(my_var) int my_var;
#define EXPAND_AS_WRITE(my_var) fprintf(fp, "%d\n", (my_var));
#define EXPAND_AS_READ(my_var) fscanf(fp, "%d\n", &(my_var));

int my_function_write()
{
    MY_VAR_LIST(EXPAND_AS_DEFINITION)
    FILE *fp;
    fp = fopen("results.dat", "a");     // open file

    if (fp == NULL) {
        printf("I couldn't open results.dat for appending.\n");
        exit(0);
    }

    MY_VAR_LIST(EXPAND_AS_WRITE)
    fclose(fp);
}

int my_function_read()
{
    MY_VAR_LIST(EXPAND_AS_DEFINITION)
    FILE *fp;
    fp = fopen("results.dat", "r");     // open file

    if (fp == NULL) {
        printf("I couldn't open results.dat for appending.\n");
        exit(0);
    }

    MY_VAR_LIST(EXPAND_AS_READ)
    fclose(fp);
}

所以要附加一个新的 var,你只需要更新你的 VAR_LIST。

我没有尝试编译我的代码,所以可能存在一些语法错误,但它应该是这样工作的。

【讨论】:

  • 谢谢,这是我问的最接近的谢谢,看看它是如何完成的。
【解决方案2】:

为什么是预处理器?你可以在代码中做到这一点,像这样

#define READ 0
#define WRITE 1

void do_some_io( int action )
{
    FILE *fp; int someVar = 1;

    fp = fopen("results.dat", (action == WRITE ? "a" : "r") );     // open file

    if (fp == NULL) {
        printf("I couldn't open results.dat for io.\n");
        exit(0);
    }

    if ( action == WRITE )
        fprintf(fp, "%d\n", someVar);   // write to file
    else
        fscanf(fp, "%d\n", &someVar);       // read from file
    fclose(fp);                     // and close
}

【讨论】:

  • 很好的答案,但为什么要预处理? enum action { READ, WRITE };.
  • 这里是预处理器和无预处理器常量之间的战争。我喜欢我的方式,但恕我直言没关系。
【解决方案3】:

查看您的代码,我认为这不值得,因为其中存在太多差异(“a”与“r”在打开时,不同的错误消息,printf 与 scanf,额外的 printf) .如果有人必须在一年后阅读或调试它,整个事情将变得一团糟,甚至更加难以理解。

但是,出于教育目的:

#define MYFUNC(NAME,VARPART1,VARPART2) \
  void NAME () { \
      int a= 0; \
      VARPART1; \
      VARPART2; \
  }

// make a print function
MYFUNC(printit, printf("%d", a), return);

// make a scan function:
MYFUNC(scanit, scanf("%d", &a), *global= a);

将使用一个宏创建两个不同的函数,例如第一个是:

  void printit () { 
      int a= 0; \
      printf("%d", a); 
      return; 
  }

【讨论】:

  • 谢谢你,很高兴看到原则上如何做到这一点。不幸的是,我会一次加载几个变量(我已经更新了我的示例代码)并且只想创建一对函数。
猜你喜欢
  • 1970-01-01
  • 2012-06-17
  • 1970-01-01
  • 1970-01-01
  • 2012-05-10
  • 2011-03-05
  • 1970-01-01
  • 2013-07-27
  • 2014-03-07
相关资源
最近更新 更多