Hemmer
Hemmer

Reputation: 1376

Avoid code duplication in read/write functions using preprocessor

If I have a pair of long functions:

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

Is there a way I can (ab)use the preprocessor to avoid duplicating read and write code? In other words, is there a way to generate pairs of fprintf(fp, "%d\n", someVar) and fprintf(fp, "%d\n", someVar) in the write() and read() functions respectively?

EDIT: this could equally apply to allocating/deallocating a whole load of memory, e.g. http://pastebin.com/wdAnHfWx. Basically any task which has a lot of code repetition between two complementary, but simple functions.

Upvotes: 0

Views: 181

Answers (3)

Jonatan Goebel
Jonatan Goebel

Reputation: 1139

There is a technique known as X Macros that may fit to your needs. You can check a basic information of how it works in wikipedia (http://en.wikipedia.org/wiki/X_Macro).

Following the wiki explanation, you could create a VAR_LIST, and later expand this list as read or write.

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

So to append a new var, you just need to update your VAR_LIST.

I did not tried to compile my code, so there is probably some syntax error, but that is the way it should work.

Upvotes: 1

Michal Bukovy
Michal Bukovy

Reputation: 420

Why preprocessor? You can to that right in code, something like this

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

Upvotes: 1

Nicholaz
Nicholaz

Reputation: 1429

Looking at your code, I'd say it's not worth the effort, because there are too many differences in it ("a" vs. "r" in open, different error messages, printf vs. scanf, extra printf). The whole thing will be messy to create and even more messy to undestand if someone will have to read or debug it a year later.

However, for educational purposes:

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

will create two different functions with one macro, e.g the first will be:

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

Upvotes: 0

Related Questions