I am used to Objective C header files and am not sure how C header files are used in terms of good practice.
Where would one #include other source files, in the header file or the .c file?
Does the same idea apply to C where .c files include their own header files. and other files include the .h files of the source they want to include?
Is there anything equivalent to the @class usage in Objective-C?
Is it good practice to declare pointers in the .h file and initialize them/alloc them in the .c file?
You normally distinguish between source and header files in the same way that Objective-C differentiates between implementation (.m) and interface (.h) files. Source files contain everything that may execute, header files contain enough information about symbols that other source files know how to communicate with that source file.
Header files often include other header files, so you’ll see
#includein both source and implementation files.#includeoperates exactly like#importexcept that it doesn’t automatically check whether you’ve #included the same file twice. So C header files often look something like:Which has the same effect of ensuring the main body of the header file is included only once.
EDIT: more on this, as per request. Obviously you’d never do something like:
But you can easily end up with something like:
Where both FirstComplexThing.h and SecondComplexThing.h rely on something inside and hence #include SimpleThing.h. So you end up with SimpleThing.h #included twice, without making any sort of error or following any bad design pattern.
C compilers work just like Objective-C compilers — each source file is compiled on its own, in isolation, with no overview until the linker comes along. #include is a preprocessor directive that has the same logical effect as copying the contents of the named file and pasting them into your source file at that location, so if you end up the same file #included twice you’ll probably end up with something like:
And the compiler will stop with an error that the same thing is declared twice. #import in Objective-C avoids that by being shorthand for ‘#include, but only if you haven’t already #included that file’. The C #ifndef/#define/#endif convention achieves the same thing as #import because the #ifndef/#endif pair say that the stuff in between should be passed on to the compiler if the nominated preprocessor symbol (__SOME_SYMBOL in my example; it tends to be a name derived from the name of that header file but exact conventions vary) hasn’t been defined. It won’t have been the first time the construct is encountered. Because it is defined inside the construct, it will have been when the same #ifndef is encountered the second time, so the stuff up to the matching #endif won’t be passed on.
Although it’s a question of style, it is very often the case that each C file has one H file that is directly connected to it.
There are no classes in C, obviously, but if you mean a construct like:
That’s actually the normal C distinction between declarations and definitions. You’ll have a problem if you do something like:
Because the compiler doesn’t have enough information. It doesn’t know how large SomeStruct should be, so it can’t work out how SomeOtherStruct should be laid out. However, this is completely valid:
Because the size of a pointer is always known, irrespective of what it is pointing to. You’ll often see that C libraries with opaque types describe those types by pointer only (sometimes to
void *, but not always — e.g. stdio.h usesFILE *) or just give you an integer (including OpenGL, notably). So they ensure you’ve something that the compiler will know the size of without having to tell you what data they’re associating with it or giving you any way to try to manipulate it yourself.It’s perfectly good practice to put pointers in the header file (assuming it’s good practice to expose the thing globally, obviously). The same thing is often done in Objective-C, albeit for slightly different reasons, e.g.
And:
In Objective-C that’s because you can then test identity rather than always having to test equality, but basically the same rules apply to C with respect to it being normal to put the reference (be it a pointer or whatever) that represents a thing into the header and create or declare the thing in a source file. In fact, if you start putting declarations in the header file you’ll end up with errors when the program comes to link because multiple source files will think they declare the thing.