2

I have some C code I'd like to split into a header file and a source file:

#ifndef BENCHMARK_H
#define BENCHMARK_H

#ifdef WIN32
#include <windows.h>

double get_time()
{
    LARGE_INTEGER t, f;
    QueryPerformanceCounter(&t);
    QueryPerformanceFrequency(&f);
    return (double)t.QuadPart/(double)f.QuadPart;
}

#else

#include <sys/time.h>
#include <sys/resource.h>

double get_time()
{
    struct timeval t;
    struct timezone tzp;
    gettimeofday(&t, &tzp);
    return t.tv_sec + t.tv_usec*1e-6;
}

#endif

#endif

What would be the proper format of the resulting benchmark.h and benchmark.c?

I know the header file should contain function declarations, while the source file should be where the actual function definitions reside. Would this following code be correct? Namely, should the #ifdef WIN32 directive be in both files as I have it below? Or should it all be in the .c file?

benchmark.h

#ifndef BENCHMARK_H
#define BENCHMARK_H

    #ifdef WIN32
        #include <windows.h>
    #else
        #include <sys/time.h>
        #include <sys/resource.h>
    #endif

    double get_time();

#endif

benchmark.c

#ifdef WIN32

    double get_time()
    {
        LARGE_INTEGER t, f;
        QueryPerformanceCounter(&t);
        QueryPerformanceFrequency(&f);
        return (double)t.QuadPart/(double)f.QuadPart;
    }

#else

    double get_time()
    {
        struct timeval t;
        struct timezone tzp;
        gettimeofday(&t, &tzp);
        return t.tv_sec + t.tv_usec*1e-6;
    }

#endif
galois
  • 825
  • 2
  • 11
  • 31
  • There doesn't seem to be a reason to have the `#include`s in the header, so I'd put the whole thing into the `.c` file. This is, however, a matter of opinion; both ways work. – Wintermute Feb 25 '15 at 09:35
  • Header files used by function definition should go in .c file. Interfaces (function declaration) goes in .h – Milind Dumbare Feb 25 '15 at 09:36
  • I wish people would ask more questions like this. Proper program design is very important, and it is hard to find any information about it in books etc. Most programmers just pick up "some sort of design" as they go, which is far from ideal. SO seems like the perfect place for filling that knowledge gap. Generally I'd advise to study object-oriented programming (plenty of resources on that topic) and then write your C programs according to OO design. You don't need OO language support to do a proper program design. – Lundin Feb 25 '15 at 10:27
  • Simple Answer: Put all `#define`'s and `#ifdef`'s in the header file, along with all function prototypes; i.e. `int foo(int x, int y);`. Note the semicolon at the end, this says "There WILL be a function defined of this form, but it has not been defined yet." – Gophyr Feb 25 '15 at 12:40
  • @Lundin: True that. Good structure IS really important. – Gophyr Feb 25 '15 at 12:41

2 Answers2

2

Together, a header file and a c file form a "code module" (or if you will: an ADT, a class etc).

The header file is always to be regarded as the user interface of your code, where the "user" is the programmer who is going to use your module. It shall never contain any code or variable definitions, period.

While the c file contains the actual implementation, which is of no interest to the user, and should not be of any concern to them. The c file should use private encapsulation and everything that the user need not know should be in that file.

The above is how you design C programs, or any program in any language. This is not subjective, it is not opinion-based, it is the only way. If you are doing your program design differently, you are doing it wrong.


As for your specific program, it should be designed in the following way:

benchmark.h

#ifndef BENCHMARK_H
#define BENCHMARK_H

    double get_time (void);
    /* documentation about how this function is used should be put here */

#endif

benchmark.c

#include "benchmark.h"

 /*** Include files ***/
#ifdef WIN32
    #include <windows.h>
#else
    #include <sys/time.h>
    #include <sys/resource.h>
#endif

/*** Other stuff, for example constants, typedefs, static file scope variables ***/


/*** function definitions ***/

#ifdef WIN32

    double get_time (void)
    {
        LARGE_INTEGER t, f;
        QueryPerformanceCounter(&t);
        QueryPerformanceFrequency(&f);
        return (double)t.QuadPart/(double)f.QuadPart;
    }

#else

    double get_time (void)
    {
        struct timeval t;
        struct timezone tzp;
        gettimeofday(&t, &tzp);
        return t.tv_sec + t.tv_usec*1e-6;
    }

#endif

Note that double get_time() means "function that accepts any parameter" in C. That is poor style, use void instead. C and C++ are different in this regard. In C++, func() and func(void) mean the same thing.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • Where should these files go in terms of the structure of a typical program? Also, what do you think about the comment on the OP about these functions being small enough to be declared with "static" and defined in the .h file? – galois Feb 25 '15 at 10:32
  • Why is the `#ifndef BENCHMARK_H` needed? A function prototype may appear any number of times. Is it just to be rigorous? – Weather Vane Feb 25 '15 at 10:39
  • @jaska What do you mean "where should these files go". Add them to your project and link them. If you are using some particular folder structure for a larger project, then put them wherever it is appropriate. It doesn't make sense whatsoever to declare any function prototype in a h file as static. Perhaps they meant inline. At any rate, inlining functions is kind of a thing of the past, using the inline keyword in modern programming is in most cases a form of pre-mature optimization. – Lundin Feb 25 '15 at 12:54
  • @WeatherVane It is simply good programming practice. You should always have header guards in every single header file you ever write. – Lundin Feb 25 '15 at 12:55
1

I would simplify it to this, the only thing needed in the header file is the function prototype.

benchmark.h

double get_time();

benchmark.c

#ifdef WIN32
#include <windows.h>
#include "benchmark.h"

double get_time()
{
    LARGE_INTEGER t, f;
    QueryPerformanceCounter(&t);
    QueryPerformanceFrequency(&f);
    return (double)t.QuadPart/(double)f.QuadPart;
}

#else

#include <sys/time.h>
#include <sys/resource.h>
#include "benchmark.h"

double get_time()
{
    struct timeval t;
    struct timezone tzp;
    gettimeofday(&t, &tzp);
    return t.tv_sec + t.tv_usec*1e-6;
}

#endif
Weather Vane
  • 33,872
  • 7
  • 36
  • 56