jump to navigation

c-faq review and a chinese translation (1.7) January 26, 2007

Posted by TSAI HONG-BIN in Programming.
trackback

please refer to http://c-faq.com/decl/decldef.html

1.7 What’s the best way to declare and define global variables and functions?

 

First, though there can be many declarations (and in many translation units) of a single global variable or function, there must be exactly one definition. (Strictly speaking, it is also possible to have zero definitions, since it is permissible to have external declarations, without any matching definitions, for functions or variables which are never used.) For global variables, the definition is the declaration that actually allocates space, and provides an initialization value, if any. For functions, the definition is the “declaration” that provides the function body. For example, these are declarations:

extern int i;

extern int f();

and these are definitions:

int i = 0;

int f(){
return 1;
}

(Actually, the keyword extern is optional in function declarations; see question 1.11.)

 

When you need to share variables or functions across several source files, you will of course want to ensure that all definitions and declarations are consistent. The best arrangement is to place each definition in some relevant .c file. Then, put an external declaration in a header (“.h”) file, and #include it wherever the declaration is needed. The .c file containing the definition should also #include the same header file, so the compiler can check that the definition matches the declarations.

 

This rule promotes a high degree of portability: it is consistent with the requirements of the ANSI C Standard, and is also consistent with most pre-ANSI compilers and linkers. (Unix compilers and linkers typically use a “common model” which allows multiple definitions, as long as at most one is initialized; this behavior is mentioned as a “common extension” by the ANSI Standard, no pun intended. A few very old systems might once have required an explicit initializer to distinguish a definition from an external declaration.)

 

It is possible to use preprocessor tricks to arrange that a line like

DEFINE(int, i);

need only be entered once in one header file, and turned into a definition or a declaration depending on the setting of some macro, but it’s not clear if this is worth the trouble, especially since it’s usually a better idea to keep global variables to a minimum.

 

It’s not just a good idea to put global declarations in header files: if you want the compiler to be able to catch inconsistent declarations for you, you must place them in header files. In particular, never place a prototype for an external function in a .c file–if the definition of the function ever changes, it would be too easy to forget to change the prototype, and an incompatible prototype is worse than useless.

See also questions 1.24, 10.6, 17.2, and 18.8.

References: K&R1 Sec. 4.5 pp. 76-7
K&R2 Sec. 4.4 pp. 80-1
ISO Sec. 6.1.2.2, Sec. 6.7, Sec. 6.7.2, Sec. G.5.11
Rationale Sec. 3.1.2.2
H&S Sec. 4.8 pp. 101-104, Sec. 9.2.3 p. 267
CT&P Sec. 4.2 pp. 54-56

 

宣告及定義全域變數和函式最好的方法是什麼?

首先,雖然一個全域變數或函式可以宣告多次,但只能有一個定義。(註腳:嚴格說來,沒有定義也是有可能的。因為對於從未使用的變數或函式來說,在外部的宣告時沒有提供相對應的定義是被允許的。) 對全域變數來說,其定義指的是實際在配置空間,並提供初始值的宣告部份。至於函式,其定義即為提供函式內容的宣告部份。舉例來說,以下是宣告:

extern int I;

extern int f();

而以下即是定義:

int i = 0;

int f( ){
return 1;

}

事實上,extern 在函式宣告時是選擇性的。

若你需要在數個不同的原始碼檔案間分享變數或函式,你要確定所有的宣告和定義一致。最好的方法是把定義放在某個固定的 .c 檔裡,然後把外部宣告放進表頭檔,當需要使用該變數時 #include 進來。那個包含定義的 .c 檔應該也 #include 同一個表頭檔,如此編譯器可以檢查定義和宣告相符。

 

這個原則是提供高度的可攜性,不僅和ANSI C的標準一致,同時和大部份 pre-ANSI 的編譯器和連結器一致。 (UNIX 下的編譯器和連結器基本上是使用”common model”,使允許(對全域變數)具多重定義,但最多只有一個可以被初始化。這個動作在ANSI 標準裡被稱為”common extension”。一些非常舊的系統可能要求明確的初始器來從外部宣告中分辨出確切的定義)

 

使用預先處理的手法來安排像

DEFINE(int, i);

的程式碼是可行的,只需要在表頭檔輸入一次,即成為根據某個巨集所設計好的定義或宣告,但這樣做值不值得,會不會產生問題還待考慮,尤其是,普遍認為全域變數越少越好。

 

將全域的宣告放在表頭檔並不只是好主意而已:如果你希望編譯器能為你截取到不一致的宣告,你必須將它們放在表頭檔。特別是,不要將某個外部函式的原型 (按:指的是函式的定義部份) 放在一個.c檔裡,特別是當這個函式的定義不斷改變。忘記修改這個原型是非常容易的事,而且一個不相容的原型比沒用的原型還糟。

 

Advertisements

Comments»

No comments yet — be the first.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: