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.

5
  • See stackoverflow.com/questions/1164652/…
    – Mihai8
    Commented Jun 5, 2013 at 9:42
  • i cant understand for what you want this .
    – qwr
    Commented Jun 5, 2013 at 9: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: pastebin.com/wdAnHfWx
    – Hemmer
    Commented Jun 5, 2013 at 9: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. Commented Jun 5, 2013 at 10:00
  • Yes that's true, I was just hastily throwing together example code for here!
    – Hemmer
    Commented Jun 5, 2013 at 10:01

3 Answers 3

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.

1
  • Thanks, this is the closest to what I asked thanks, neat to see how it is done.
    – Hemmer
    Commented Jun 5, 2013 at 13:45
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
}
2
  • Good answer, but why preprocessor? enum action { READ, WRITE };.
    – ugoren
    Commented Jun 5, 2013 at 10:28
  • And here comes the war between preprocessor and no-preprocessor constants. I like it my way, but imho it doesn't matter. Commented Jun 5, 2013 at 10:32
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; 
  }
1
  • 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
    Commented Jun 5, 2013 at 10:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.