Code reuse without obfuscation

This is a discussion on Code reuse without obfuscation within the C Programming forums, part of the General Programming Boards category; Hi all -- long time no see, I have a little C assignment from a training program I'm in. I'm ...

  1. #1
    Kiss the monkey. CodeMonkey's Avatar
    Join Date
    Sep 2001
    Posts
    904

    Code reuse without obfuscation

    Hi all -- long time no see,

    I have a little C assignment from a training program I'm in. I'm used to C++. My program is essentially two methods in main() that do very similar things to two arrays of structures (different structures). In C++, I could combine these two tasks into one template function, the only fundamental difference being the two different structure types. Is there any way to generalize this code so that it need be expressed only once, or will I do more harm than good? I'm wondering for the sake of C, with which I am not familiar. Here is most of main():

    Code:
    /* If only C had templates like C++.... */
    	/* These two sections of code are similar. */
    
    	/* read stock file */
    	stock_file = fopen(argv[1], "r");
    	if(stock_file == NULL)
    		fopen_abort(argv[1]);
    	stock_file_nlines = n_lines(stock_file);
    	stocks = (stock*)calloc(stock_file_nlines, sizeof(stock));
    	if(stocks == NULL)
    		memory_abort();
    	n_stocks = read_stocks(stock_file, stocks);
    	qsort(stocks, n_stocks, sizeof(stock), stock_cmp);
    
    	/* process trades in trade file */
    	trade_file = fopen(argv[2], "r");
    	if(trade_file == NULL)
    	{
    		free(stocks);
    		fopen_abort(argv[2]);
    	}
    	trade_file_nlines = n_lines(trade_file);
    	trades = (trade*)calloc(trade_file_nlines, sizeof(trade));
    	if(trades == NULL)
    		memory_abort();
    	n_trades = process_trades(trade_file, trades, stocks, n_stocks);
    	qsort(trades, n_trades, sizeof(trade), trade_cmp);
    I see how I could consolidate the file-opening and fopen() error checking, but what about the rest?

    Thanks.
    "If you tell the truth, you don't have to remember anything"
    -Mark Twain

  2. #2
    Programming Wraith GReaper's Avatar
    Join Date
    Apr 2009
    Location
    Greece
    Posts
    1,625
    Well, abstract programming in C is difficult and messy, therefore I advice you not to try it.
    Should you tried it though, for the sake of learning , you need a void pointer for the struct and the size of it. You may also consider passing the function an additional "flag" parameter to determine between the two or more. But I say once more that it's difficult and messy!

    EDIT: It's error-prone too!
    Last edited by GReaper; 06-22-2011 at 01:16 AM.
    Devoted my life to programming...

  3. #3
    Registered User
    Join Date
    Jun 2005
    Posts
    6,311
    In C there are preprocessor macros. They are not as safe as C++ templates (i.e. it is easier to misuse them) but they can be used to achieve similar things.
    Right 98% of the time, and don't care about the other 3%.

  4. #4
    Registered User ssharish2005's Avatar
    Join Date
    Sep 2005
    Location
    Cambridge, UK
    Posts
    1,682
    Yeah I agree, it should either using macros or sending in by a flag. there is nothing like function overloading in C unfortunately which makes a bit difficult to achieve stuff in C which you perhaps be done quite easily in C++.

    ssharish
    Life is like riding a bicycle. To keep your balance you must keep moving - Einstein

  5. #5
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    You repeat 3 things:

    1. Opening a file.
    2. Counting the lines.
    3. Allocating space.
    Code:
    void *ocalloc( FILE **fp, const char *fname, const char *fmode, size_t membersize )
    {
        void *rval = NULL;
        if( fp && fname && fmode )
        {
            *fp = fopen( fname, fmode );
            if( *fp )
            {
                size_t lines = linecounter( *fp );
                rval = calloc( lines, membersize );
            }
        }
        return rval;
    }
    ...
    FILE *fp;
    type *data;
    
    data = ocalloc( &fp, "myfile", "r", sizeof *data );
    if( data == NULL )
        printf( "oops" );

    Quzah.
    Last edited by quzah; 06-22-2011 at 04:26 AM. Reason: typo
    Hope is the first step on the road to disappointment.

  6. #6
    Kiss the monkey. CodeMonkey's Avatar
    Join Date
    Sep 2001
    Posts
    904
    I see. Thank you all.
    "If you tell the truth, you don't have to remember anything"
    -Mark Twain

  7. #7
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,498
    I would probably take the function pointer approach:
    Code:
    void *process_file(char *filename, size_t element_size, int (read_func)(FILE *, void *), int (cmp_func)(const void *, const void *))
    {
        int file_nlines;
        void *data;
        FILE *file;
    
        ...
        data = calloc(file_nlines, element_size);  // we don't like casting malloc/calloc in C -- see the FAQ
        ...
        n_elements = read_func(file, data);
        qsort(data, n_elements, element_size, cmp_func);
    }
    
    void do_stuff(void)
    {
        stock *stocks;
        trade *trades;
        stocks = process_file(argv[1], sizeof(stock), read_stocks, stock_cmp);
        trades = process_file(argv[2], sizeof(trade), process_trades, trade_cmp);
    }

  8. #8
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by CodeMonkey View Post
    I'm wondering for the sake of C, with which I am not familiar.
    Yes, C involves more work than C++, because it lacks certain temptations, such as templates, which are massive consumers of memory. So, when you are frustrated, think about it this way: how would I approach this in C++ if memory use were a priority and it was spec to NOT use templates?

    If you have no answer to that, it's because you've become enamoured of language features which increase programmer productivity, but waste resources. Remember, the soft "C" in C stands for ctreamlined
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  9. #9
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Quote Originally Posted by anduril462 View Post
    I would probably take the function pointer approach:
    That won't work. From the OP:
    read_stocks(stock_file, stocks);
    ....
    n_trades = process_trades(trade_file, trades, stocks, n_stocks);
    You can't have a function pointer work for two different functions that have different numbers of arguments - without making the functions something like:
    Code:
    int foo( x, ... );
    I thought of this implementation first, but it seemed too much work for what he was doing, since I could get away with what I did as an alternate.


    Quzah.
    Hope is the first step on the road to disappointment.

  10. #10
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,498
    Quote Originally Posted by quzah View Post
    That won't work...
    Yeah, somehow I totally glossed over that when I was reading the code. I guess I just assumed that "two very similar things" were more similar than they were. A less pretty version of your var args is to have an explicit parameter list for the read/process function, and just pass in dummy params (changes in green):
    Code:
    void *process_file(char *filename, size_t element_size, int (read_func)(FILE *, void *, void *, int), void *extra_data, int extra_int, int (cmp_func)(const void *, const void *))
    {
        ...
        n_elements = read_func(file, data, extra_data, extra_int);
        qsort(data, n_elements, element_size, cmp_func);
    }
    
    
    void do_stuff(void)
    {
        stock *stocks;
        trade *trades;
        stocks = process_file(argv[1], sizeof(stock), read_stocks, NULL, 0, stock_cmp);
        trades = process_file(argv[2], sizeof(trade), process_trades, stocks, n_stocks, trade_cmp);
    }
    I admit, it's ugly, but it serves the purpose without the mess of var args. Actually, I just realized that this doesn't return n_stocks, so you'd have to have an extra parameter that is handled specially if process_file is being called with the stock file, or bundle up the stocks array and count of items into a simple struct. So much for a clean, template-y solution.

  11. #11
    Registered User
    Join Date
    Jun 2005
    Posts
    6,311
    Quote Originally Posted by MK27 View Post
    Yes, C involves more work than C++, because it lacks certain temptations, such as templates, which are massive consumers of memory.
    Templates are not massive consumers of memory. There was a time when they were (about 15 years ago), but that was a reflection of the quality of implementation of compilers coupled with clumsy usage of templates: both compiler vendors and programmers, at the time, were on a learning curve with what was then a relatively new and complex language feature.
    Right 98% of the time, and don't care about the other 3%.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. funtion reuse
    By lukasjob in forum C Programming
    Replies: 6
    Last Post: 03-11-2011, 08:25 AM
  2. code reuse
    By nimitzhunter in forum C++ Programming
    Replies: 11
    Last Post: 12-19-2010, 04:18 PM
  3. reuse a socket connection
    By radeberger in forum Networking/Device Communication
    Replies: 0
    Last Post: 03-18-2009, 11:38 AM
  4. operator '>>' reuse
    By csonx_p in forum C++ Programming
    Replies: 66
    Last Post: 09-11-2008, 06:35 AM
  5. homework v.s. reuse
    By xddxogm3 in forum C++ Programming
    Replies: 2
    Last Post: 12-08-2003, 01:18 PM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21