0

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.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Hemmer
  • 1,366
  • 1
  • 18
  • 33
  • See http://stackoverflow.com/questions/1164652/printing-name-and-value-of-a-define – Mihai8 Jun 05 '13 at 09:42
  • i cant understand for what you want this . – qwr Jun 05 '13 at 09:43
  • e.g. if I want to read/write a whole load of variables and preserve the order they are written/read in, then it is a bit simpler to add 1 line of code (which expands to give a read/write version) than to add lines to both the read and write functions separately. Another (simpler) example: http://pastebin.com/wdAnHfWx – Hemmer Jun 05 '13 at 09:51
  • read() and write() are *terrible* names for functions, since they are also the names (unix) system calls (which are used internally by stdio functions). Avoid using them if you want to keep your sanity. – wildplasser Jun 05 '13 at 10:00
  • Yes that's true, I was just hastily throwing together example code for here! – Hemmer Jun 05 '13 at 10:01

3 Answers3

1

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
}
Michal Bukovy
  • 422
  • 3
  • 16
1

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.

Jonatan Goebel
  • 1,107
  • 9
  • 14
0

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; 
  }
Nicholaz
  • 1,419
  • 9
  • 11
  • Thanks for this, good to see how it could be done in principle. Unfortunately I would be loading in several variables at once (i've updated my sample code) and only want to create one pair of functions. – Hemmer Jun 05 '13 at 10:17