不要將函式的引數列表留空使用 void

假設你正在建立一個在呼叫時不需要引數的函式,並且你面臨著如何在函式原型和函式定義中定義引數列表的困境。

  • 你可以選擇將原型和定義的引數列表保持為空。因此,它們看起來就像你需要的函式呼叫語句。

  • 你在某處讀到關鍵字 void (只有少數幾個)的使用之一,就是定義不接受呼叫中任何引數的函式的引數列表。所以,這也是一個選擇。

那麼,哪個是正確的選擇呢?

答案: 使用關鍵字 void

一般建議: 如果某種語言提供某些特殊功能,你最好在程式碼中使用它。例如,使用 enums 而不是 #define 巨集(這是另一個例子)。

C11 第 6.7.6.3 節函式宣告者第 10 段規定:

void 型別的未命名引數作為列表中唯一項的特殊情況指定該函式沒有引數。

同一節的第 14 段顯示了唯一的區別:

…函式宣告符中的空列表是該函式定義的一部分,指定該函式沒有引數。函式宣告符中的空列表不是該函式定義的一部分,它指定不提供有關引數數量或型別的資訊。

K&R(pgs-72-73)為上述內容提供的簡化說明:

此外,如果一個函式宣告不包含引數,就像在
double atof(); 中那樣,那也意味著沒有任何關於 atof 的引數的假設; 所有引數檢查都已關閉。空引數列表的這種特殊含義旨在允許較舊的 C 程式使用新的編譯器進行編譯。但是將它與新程式一起使用是一個壞主意。如果函式接受引數,則宣告它們; 如果不引數,請使用 void

這就是你的函式原型應該是這樣的:

int foo(void);

這就是函式定義的方式:

int foo(void)
{
    ...
    <statements>
    ...
    return 1;
}

使用上面的 int foo() 型別宣告(即不使用關鍵字 void )的一個優點是,如果使用像 foo(42) 這樣的錯誤語句呼叫函式,編譯器可以檢測到錯誤。如果將引數列表留空,則此類函式呼叫語句不會導致任何錯誤。錯誤將無聲地傳遞,未檢測到,程式碼仍將執行。

這也意味著你應該像這樣定義 main() 函式:

int main(void)
{
    ...
    <statements>
    ...
    return 0;
}

請注意,即使使用空引數列表定義的函式不帶引數,它也不會為函式提供原型,因此如果隨後使用引數呼叫函式,編譯器將不會抱怨。例如:

#include <stdio.h>

static void parameterless()
{
    printf("%s called\n", __func__);
}

int main(void)
{
    parameterless(3, "arguments", "provided");
    return 0;
}

如果該程式碼儲存在檔案 proto79.c 中,則可以在 Unix 上使用 GCC(用於演示的 macOS Sierra 10.12.5 上的 7.1.0 版)進行編譯,如下所示:

$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -pedantic proto79.c -o proto79
$

如果使用更嚴格的選項進行編譯,則會出現錯誤:

$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -pedantic proto79.c -o proto79 
proto79.c:3:13: error: function declaration isn’t a prototype [-Werror=strict-prototypes]
 static void parameterless()
             ^~~~~~~~~~~~~
proto79.c: In function ‘parameterless’:
proto79.c:3:13: error: old-style function definition [-Werror=old-style-definition]
cc1: all warnings being treated as errors
$

如果你給函式正式原型 static void parameterless(void),那麼編譯會給出錯誤:

$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -pedantic proto79.c -o proto79 
proto79.c: In function ‘main’:
proto79.c:10:5: error: too many arguments to function ‘parameterless’
     parameterless(3, "arguments", "provided");
     ^~~~~~~~~~~~~
proto79.c:3:13: note: declared here
 static void parameterless(void)
             ^~~~~~~~~~~~~
$

道德 - 始終確保你擁有原型,並確保你的編譯器在你不遵守規則時告訴你。