开发者

C Header Files - Good Practice

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开发者_StackOverflow中文版 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 #include in both source and implementation files. #include operates exactly like #import except that it doesn't automatically check whether you've #included the same file twice. So C header files often look something like:

#ifndef __SOME_SYMBOL
#define __SOME_SYMBOL

    ... rest of header file here ...

#endif

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:

#include "File.h"
#include "File.h"

But you can easily end up with something like:

#include "FirstComplexThing.h"
#include "SecondComplexThing.h"

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:

char *somePointer; // I'm from SimpleThing.h

... lots of other things ...

char *somePointer; // I'm from SimpleThing.h

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:

@class SomeClass;

@interface SomeOtherClass: NSObject
{
      SomeClass *otherClass; // I can reference SomeClass without importing
                             // the interface file because I've declared the
                             // type above
}

- (void)whatever;
@end

That's actually the normal C distinction between declarations and definitions. You'll have a problem if you do something like:

struct SomeStruct;

struct SomeOtherStruct
{
    struct SomeStruct otherStruct;
};

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:

struct SomeStruct;

struct SomeOtherStruct
{
    struct SomeStruct *otherStruct;
};

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 uses FILE *) 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.

// interface/header file

extern NSString *someGlobalIdentifier;

And:

// implementation/source file

NSString *someGlobalIdentifier = @"somethingOrOther";

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.


->#include is working in c and objective c. ->But generally in objective c, always used #import. ->#include and #import are different, when you used #include compiler generate one separate copy of .h file, and if you used #import then compiler generate only one copy at a time

Is there anything equivalent to the @class usage in Objective-C? -> No there is no any other equivalent Is it good practice to declare pointers in the .h file and initialize them/alloc them in the .c file? -> Yes if your object is public, then you must declare in .h file, but always is good practice that initialize them it in constructor.


This is how I finally figured out how to do this properly. After long time of trying and failing at what used to be a simple thing.

    //this is the mechanics.h file

    #ifndef ProjectA_mechanics_h
    #define ProjectA_mechanics_h

    #ifdef __cplusplus
    extern "C" {
    #endif

    int funcAdd (int A, int B);


    #ifdef __cplusplus
    }
    #endif

    #endif

    // this is the mechanics.c file

    #include "mechanics.h"
    #include <math.h>

    int funcAdd (int A, int B)
    {
        return A + B;
    }

math.h is there "just because"

have fun, dang this sucked for while

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜