C/C++ extern 用法與範例

本篇 ShengYu 介紹 C/C++ extern 用法與範例。

以下 C/C++ extern 的用法與範例分為這幾部分介紹,

  • C/C++ extern 引用外部變數
  • C/C++ extern 引用外部函式

那我們開始吧!

C/C++ extern 引用外部變數

這邊介紹 C/C++ extern 引用外部變數的使用方式,這邊指的是 extern 引用外部的全域變數,這個方法使用的前提是該變數不能為 static,static 的用法之前有介紹過,假設我有 main.cpp、a.h、a.cpp、b.h、b.cpp 這幾隻檔案,在 main 函式裡呼叫 bbb 函式,bbb 函式位於 b.cpp 裡,但 bbb 函式會使用到 a.cpp 裡的全域變數 counter 的話要怎麼使用呢?

這邊 ShengYu 舉個簡單的範例,在 main.cpp 很簡單的呼叫 aaa() 函式以後,再呼叫 bbb() 函式,接下來看看這流程,

main.cpp
1
2
3
4
5
6
7
8
9
#include <stdio.h>
#include "a.h"
#include "b.h"

int main() {
aaa();
printf("%d\n", bbb(5));
return 0;
}

a.h 內容如下,很簡單的只有 aaa 函式原型宣告,

a.h
1
void aaa();

a.cpp 內容如下,counter 變數宣告是在 a.cpp 裡的全域變數,呼叫 aaa 函式則會增加 counter,注意的是這邊 counter 如果宣告成 static 則其它 *.cpp 則無法引用,這用途相似於 class 裡的 private 變數的概念,

a.cpp
1
2
3
4
5
int counter = 0;

void aaa() {
counter++;
}

b.h 內容如下,很簡單的只有 bbb 函式原型宣告,

b.h
1
int bbb(int x);

b.cpp 內容如下,使用 extern 來標記/引用 counter 這個全域變數,所以這邊 b.cpp 實際上不會產生一個 counter 變數的實體,在編譯連結時期會引用 a.o 的 counter,

b.cpp
1
2
3
4
5
extern int counter;

int bbb(int x) {
return x + counter;
}

使用以下 g++ 指令進行編譯與連結,順序為將 a.cpp 編譯成 a.o 中繼檔,將 b.cpp 編譯成 b.o 中繼檔,將 main.cpp 編譯成 main.o 中繼檔,最後將這些中檔連結起來輸出成 a.out 執行檔,

1
2
3
4
g++ -c a.cpp
g++ -c b.cpp
g++ -c main.cpp
g++ -o a.out main.o a.o b.o

執行 a.out 的結果輸出如下,

1
6

由上面的實驗可以了解 C/C++ extern 的用法與用途,那反過來想如果今天我的全域變數不想給別人 extern 時就可以加上 static。
延伸閱讀:C/C++ static 的 5 種用法

C/C++ extern 引用外部函式

既然 extern 有引用外部變數的方式,那麼有沒有 extern 引用外部函式呢?

結果是有的!C/C++ extern 引用外部函式跟引用外部變數用法差不多,這邊就簡單介紹一下,基本上要 extern 的函式前提是該函式不能為 static,這點跟 extern 外部變數一樣,函式前面加上 static 的用意就是希望它只能在這支原始檔裡使用,不想給別人呼叫,有點像 class 裡的 private function 的味道,所以要 extern 函式要先確定一下這件事,否則會編譯失敗,

這邊就簡單舉例一下,跟前述例子差不多,只是這次沒有 a.h 跟 b.h,而且 a.cpp 新增了 print_counter 函式來印出 counter,以下是 a.cpp 內容,

a.cpp
1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
int counter = 0;

static void print_counter(int c) {
printf("counter: %d\n", c);
}

void aaa() {
counter++;
print_counter(counter);
}

b.cpp 內容如下,跟前述例子一樣,

b.cpp
1
2
3
4
5
extern int counter;

int bbb(int x) {
return x + counter;
}

main.cpp 內容如下,可以看到在 main.cpp 裡可以使用 extern 引用 aaa 與 bbb 函式,extern 引用函式後就可以順利使用,編譯跟執行是沒有問題的!但是如果要 extern print_counter 函式的話編譯時就會連結錯誤,

main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>

extern void aaa();
extern int bbb(int x);
//extern void print_counter(int c); // 連結錯誤, 因為 print_counter 是 static

int main() {
aaa();
printf("%d\n", bbb(5));
//print_counter(10); // 連結錯誤, 因為 print_counter 是 static
return 0;
}

編譯的指令如下,跟前述例子一樣,

1
2
3
4
g++ -c a.cpp
g++ -c b.cpp
g++ -c main.cpp
g++ -o a.out main.o a.o b.o

執行 a.out 的結果輸出如下,

1
2
counter: 1
6

如果嘗試在 main.cpp extern print_counter 並呼叫 print_counter 函式的話,編譯時會連結錯誤,錯誤訊息如下,

1
2
3
main.o: In function `main':
main.cpp:(.text+0x2a): undefined reference to `print_counter(int)'
collect2: error: ld returned 1 exit status

延伸閱讀:C/C++ static 的 5 種用法

C/C++ extern 還有另一種用法是 extern "C",下次有機會再給大家介紹。
以上就是 C/C++ extern 用法與範例介紹,
如果你覺得我的文章寫得不錯、對你有幫助的話記得 Facebook 按讚支持一下!

其它參考
https://medium.com/@alan81920/c-c-%E4%B8%AD%E7%9A%84-static-extern-%E7%9A%84%E8%AE%8A%E6%95%B8-9b42d000688f
https://docs.microsoft.com/zh-tw/cpp/cpp/extern-cpp?view=msvc-170
https://mitblog.pixnet.net/blog/post/37137361

其它相關文章推薦
如果你想學習 C++ 相關技術,可以參考看看下面的文章,
C/C++ 新手入門教學懶人包
C/C++ static 的 5 種用法