2011-04-05 37 views
2

我習慣於Objective C頭文件,並不確定C頭文件在良好實踐方面的用法。C頭文件 - 良好實踐

哪裏會有一個#include其他源文件,在頭文件或.c文件中?

這個想法是否適用於C語言,其中.c文件包含它們自己的頭文件。其他文件包括他們想要包含的源文件的.h文件?

Objective-C中是否有任何與@class用法等價的東西?

在.h文件中聲明指針並初始化它們/將它們分配在.c文件中是不是很好的做法?

回答

10

您通常以Objective-C區分實現(.m)和接口(.h)文件的方式區分源文件和頭文件。源文件包含可執行的所有內容,頭文件包含有關其他源文件知道如何與該源文件進行通信的符號的足夠信息。

頭文件通常包含其他頭文件,因此您會在源文件和實現文件中看到#include#include的操作與#import完全一樣,不同之處在於它不會自動檢查您是否包含同一個文件兩次。因此C頭文件通常如下所示:

#ifndef __SOME_SYMBOL 
#define __SOME_SYMBOL 

    ... rest of header file here ... 

#endif 

這與確保頭文件主體只包含一次的效果相同。

編輯:更多關於此,根據請求。顯然,你永遠不會做這樣的事情:

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

但是你可以很容易地像結束:

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

如果雙方FirstComplexThing.h和SecondComplexThing.h靠裏面的東西,因此的#include SimpleThing.h。所以你最終得到了SimpleThing.h #included兩次,沒有任何錯誤或跟隨任何不良的設計模式。

C編譯器就像Objective-C編譯器一樣工作 - 每個源文件都是獨立編譯的,只有連接器出現時纔會進行概述。#include是一個預處理器指令,它具有與複製指定文件內容並將其粘貼到源文件中相同的邏輯效果,因此,如果最終包含兩次相同的文件,則可能會得到一些結果如:

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

... lots of other things ... 

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

並且編譯器將停止並且聲明兩次相同的事件。 Objective-C中的#import避免了#include的縮寫,但只有當你還沒有#include該文件時。 C#ifndef/#define /#endif約定實現與#import相同的功能,因爲#ifndef/#endif對錶示如果指定的預處理器符號(在我的示例中爲__SOME_SYMBOL;它往往是一個名稱來源於該頭文件的名稱,但確切的約定有所不同)尚未定義。這不會是第一次遇到構造。因爲它是在構造內部定義的,所以在第二次遇到相同的#ifndef時,所以到匹配的#endif的東西不會被傳遞。

儘管這是一個風格問題,但每個C文件都有一個直接連接到它的H文件的情況經常出現。

已經有C沒有階級,很明顯,但如果你的意思是一個結構,如:

@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 

這實際上是聲明和定義之間的正常的C區別。如果您執行類似操作,則會遇到問題:

struct SomeStruct; 

struct SomeOtherStruct 
{ 
    struct SomeStruct otherStruct; 
}; 

因爲編譯器沒有足夠的信息。它不知道SomeStruct應該有多大,所以它不能算出SomeOtherStruct應該如何佈局。但是,這是完全有效的:

struct SomeStruct; 

struct SomeOtherStruct 
{ 
    struct SomeStruct *otherStruct; 
}; 

因爲指針的大小總是已知的,無論它指向什麼。您經常會看到具有不透明類型的C庫僅通過指針描述了這些類型(有時可能是void *,但並非總是如此 - 例如stdio.h使用FILE *),或者只是給出一個整數(包括OpenGL,值得注意)。所以他們確保你有一些東西,編譯器會知道它的大小,而不必告訴你他們與它關聯的數據或給你任何方法來自己操縱它。

將指針放在頭文件中是非常好的做法(假設很明顯全局公開這個東西是很好的做法)。同樣的事情經常在Objective-C中完成,儘管原因稍有不同,例如,

// interface/header file 

extern NSString *someGlobalIdentifier; 

和:

// implementation/source file 

NSString *someGlobalIdentifier = @"somethingOrOther"; 

在Objective-C那是因爲你可以再試驗的身份,而不是總是要測試的平等,但基本上是相同的規則適用於C相對於它是正常將代表事物的引用(無論是指針還是其他)引入標題中,並在源文件中創建或聲明該事物。實際上,如果你開始在頭文件中放置聲明,那麼當程序開始鏈接時,最終會出現錯誤,因爲多個源文件會認爲它們聲明瞭它。

+0

信息化的回答,謝謝。我不完全瞭解如何使用#ifndef __SOME_SYMBOL #define __SOME_SYMBOL來檢查頭文件是否已被複制。我想這樣做,顯然刪除不需要的副本。你可以進一步詳細一點。 :) – jarryd 2011-04-05 11:39:42

+1

我編輯了我的答案;希望能幫助到你! – Tommy 2011-04-05 12:07:45

+0

非常詳細的解釋,謝謝@Tommy! – efimovdk 2016-11-24 23:24:18

1

- >#include正在c和目標c中工作。 - >但一般在目標c中,總是使用#import。 - >#include和#import是不同的,當你使用#include編譯器生成一個單獨的.h文件副本,並且如果你使用#import,那麼編譯器一次只能生成一個副本

是否有任何等效Objective-C中的@class用法? - >不,沒有任何其他等效的 在.h文件中聲明指針並初始化它們/將它們分配到.c文件中是否是一種好的做法? - >是的,如果你的對象是公開的,那麼你必須在.h文件中聲明,但總是在構造函數中初始化它們的好習慣。

0

這就是我最終想出如何正確做到這一點的方法。經過很長時間的嘗試和失敗曾經是一件簡單的事情。

//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中是存在的 「只是因爲」

玩得開心,這個黨爲吸引而