欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C/C++?extern關(guān)鍵字用法示例全面解析

 更新時間:2023年01月04日 09:37:39   作者:小余的自習(xí)室  
這篇文章主要為大家介紹了C/C++?extern關(guān)鍵字用法示例全面解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

前言

extern 是C/C++語言中表明全局變量或者函數(shù)作用范圍(可見性)的關(guān)鍵字,編譯器收到extern通知,則其聲明的變量或者函數(shù)可以在本模塊或者其他模塊使用。

對于函數(shù)而言,由于函數(shù)的聲明如“extern int method();”與函數(shù)定義“int method(){}”可以很清晰的區(qū)分開來,為了簡便起見,可以把extern關(guān)鍵字省略,于是有了我們常見的函數(shù)聲明方式“int method();”,然而對于變量并非如此,變量的定義格式如“int i;”,聲明格式為“extern int i;”,如果省略extern關(guān)鍵字,就會造成混亂,故不允許省略。

一般用法

在本模塊中使用:

extern int a;
extern int b;
int maxbb(int l,int r) {
    return l > r ? l : r;
}
int main() {
    cout << maxbb(a, b) << endl;
}

int a = 10;
int b = 20;

當(dāng)前模塊的main函數(shù)在a和b之前定義,所以main函數(shù)對a和b是沒有訪問權(quán)限的,可以在main之前定義

extern int a;
extern int b;

這樣就可以正常訪問到a和b了。

跨模塊中

在模塊1 _extern.cpp中定義:

extern int _a = 10;
extern int _b = 20;

int maxAB(int a,int b) {
    return a > b ? a : b;
}

在模塊2 main.cpp中定義:

extern int _a;
extern int _b;
int maxAB(int a,int b);
int main() {
    cout << "a:" << _a << " b:" << _b << endl;
    cout << maxAB(100,200) << endl;
}

結(jié)果:
a:10 b:20
200

看到使用extern關(guān)鍵字使用到了外部模塊_extern.cpp中的全局變量以及函數(shù)。

標(biāo)準(zhǔn)定義使用extern關(guān)鍵字的步驟為:

  • 1.定義一個.h文件用來聲明需要提供外部訪問的變量或者函數(shù)。
module1.h
extern int _a;
extern int _b;
int maxAB(int a, int b);

2.定義一個.cpp文件來初始化全局變量或者函數(shù)的實現(xiàn)

module1.cpp

#include "module1.h"

int _a = 100;
int _b = 200;

int maxAB(int x, int y) {
    return x > y ? x : y;
}

3.在需要使用到的地方使用extern關(guān)鍵字修飾。

//main.cpp
extern int _a;
extern int _b;
int maxAB(int a,int b);
int main() {
cout << "a:" << _a << " b:" << _b << endl;
cout << maxAB(100,200) << endl;
}

運行結(jié)果:
a:100 b:200
200

如果我們把module1.h中如下定義:

extern int _a = 100;
extern int _b = 200;

這樣肯定會報錯的,因為extern int _a是變量聲明,而extern int _a = 100則是變量聲明和定義。 因為module1.cpp中是將"module1.h" include到cpp中的,如果在.h中聲明和定義即使用extern int _a = 100方式,則會引起重復(fù)定義,而extern int _a是變量聲明,并非定義,所有不會重復(fù)。

extern 使用過程中的一些注意事項

這里引用掘友出的題:

數(shù)組通過外部聲明為指針時,數(shù)組和指針是不能互換使用的;那么請思考一下,在 A 文件中定義數(shù)組 char a[100];在 B 文件中聲明為指針:extern char *a;此時訪問 a[i],會發(fā)生什么;

先說結(jié)果,會引起 segmentation fault 報錯;

這里涉及到了數(shù)組與指針的區(qū)別

數(shù)組與指針的區(qū)別

數(shù)組變量和枚舉常量一樣都屬于符號常量。注意,不是數(shù)組變量這個符號的值是那塊內(nèi)存的首地址, 而是數(shù)組變量這個符號本身代表了首地址,它就是這個地址值。這就是數(shù)組變量屬于符號常量的意義所在。

由于數(shù)組變量是一個符號常量,所以其可以看做是右值,而指針作為變量,只能看作為左值。 右值永遠(yuǎn)不等于左值,所以將指針賦予數(shù)組常量是不合法的。

例如:char a[] 中的 a 是常量,是一個地址,char *a 中 a 是一個變量,一個可以存放地址的變量。

extern 聲明全局變量的內(nèi)部實現(xiàn)

被extern修飾的全局變量,在編譯期不會分配空間,而是在鏈接的時候通過索引去別的文件中查找索引對應(yīng)的地址。假設(shè)文件中聲明了一個:

extern char a[];

這是一個外部變量的聲明,聲明了一個外部的字符數(shù)組,編譯器看到這玩意時不會立即給a分配空間,而是等鏈接器進(jìn)行尋址,編譯器會將所有關(guān)于a的引用化為一個不包含類型的標(biāo)號,編譯完成后會得到一個目標(biāo)中間產(chǎn)物a.o,但是此時a.o中關(guān)于a還是一個無類型標(biāo)號,鏈接器連接的時候發(fā)現(xiàn)這個標(biāo)號,會去其他 中間產(chǎn)物中查找和這個標(biāo)號對應(yīng)的地址,找到之后替換這個標(biāo)號。最后鏈接為一個可執(zhí)行的文件。

extern char * a;

這也是一個外部變量的聲明,它聲明了一個字符指針。編譯以及鏈接過程和前面字符數(shù)組過程類似,只是此時鏈接器在尋找符號地址的時候,找到的是前面聲明的 extern char a[] 字符數(shù)組,這里就有問題了 :由于在這個文件中聲明的 a 是一個指針變量而不是數(shù)組,鏈接器的行為實際上是把指針 a 自身的地址定位到了另一個 .cpp 文件中定義的數(shù)組首地址上, 而不是我們所希望的把數(shù)組的首地址賦予指針 a。(這很容易理解:指針變量也需要占用空間,如果說把數(shù)組的首地址賦給了指針 a,那么指針 a 本身在哪里存放呢?) 這就是癥結(jié)所在了。所以此例中指針 a 的內(nèi)容實際上變成了數(shù)組 a 首地址開始的 4 字節(jié)表示的地址

上述加粗部分的可以理解為,鏈接器認(rèn)為 a 變量本身的內(nèi)存位置是數(shù)組的首地址,但其實 a 的位置是其他位置,其內(nèi)容才是數(shù)組首地址。

這里著重要理解的是:指針的地址以及指針的內(nèi)容的區(qū)別,指針本身也存在地址,鏈接器將數(shù)組的首地址賦予了指針本身,這樣肯定是不行的。

舉個例子,定義 char a[] = "abcd",則外部變量 extern char a[] 的地址是 0x12345678 (數(shù)組的起始地址), 而 extern char *a 是重新定義了一個指針變量 a,其地址可能是 0x87654321,因此直接使用 extern char *a 是錯誤的。

通過上述分析,我們得到的最重要的結(jié)論是:使用 extern 修飾的變量在鏈接的時候只找尋同名的標(biāo)號,不檢查類型,所以才會導(dǎo)致編譯通過,運行時出錯。

extern "C"

extern "C"的真實目的是實現(xiàn)類C和C++的混合編程。在C++源文件中的語句前面加上extern "C",表明它按照類C的編譯和連接規(guī)約來編譯和連接,而不是C++的編譯的連接規(guī)約。這樣在類C的代碼中就可以調(diào)用C++的函數(shù)or變量等。(注:我在這里所說的類C,代表的是跟C語言的編譯和連接方式一致的所有語言)

C和C++互相調(diào)用

前面我們說了extern “C”是為了實現(xiàn)C和C++混編,接下來就來講解下C與C++如何相互調(diào)用,在講解相互調(diào)用之前,我們先來了解C和C++編譯和鏈接過程的差異。

C++的編譯和鏈接

大家都知道C++是一個面向?qū)ο蟮木幊谭绞?,而面向?qū)ο笞詈诵牡奶匦跃褪侵剌d,函數(shù)重載給我們帶來了很大便利性。假設(shè)定義如下函數(shù)重載方法:

void log(int i);
void log(char c);
void log(float f);
void log(char* c);

則在編譯后:

_log_int
_log_char
_log_float
_log_string

編譯后的函數(shù)名通過帶上參數(shù)的類型信息,這樣連接時根據(jù)參數(shù)就可以找到正確的重載方法。

C++中給的變量編譯也是這樣一個過程,如全局變量會編譯為g_xx,類變量編譯為c_xx.連接時也是按照這種機制去查找對應(yīng)的變量的。

C的編譯和連接

C語言中并沒有重載和類這些特性,故不會像C++一樣將log(int i)編譯為log_int,而是直接編譯為log函數(shù),當(dāng)C++去調(diào)用C中的log(int i)方法時,會找不到_log_int方法,此時extern “C”的作用就體現(xiàn)出來了。

下面來看下C和C++是如何互相調(diào)用的。

C++中調(diào)用C的代碼

假設(shè)一個C的頭文件cHeader.h中聲明了一個函數(shù)_log(int i),如果C++要調(diào)用它,則必須添加上extern關(guān)鍵字。代碼如下:

//cHeader.h
#ifndef C_HEADER
#define C_HEADER
extern void _log(int i);
#endif // !C_HEADER

在對應(yīng)的cHeader.c文件中實現(xiàn)_log方法:

//cHeader.c
#include "cHeader.h"
#include <stdio.h>

void _log(int i) {
    printf("cHeader %d\n", i);
}

在C++中引用cHeader中的_log方法:

//main.cpp
extern "C" {
    //void _log(int i);
    #include "cHeader.h"
}
int main() {
    _log(100);
}

linux執(zhí)行上述文件的命令為:

  • 1.首先執(zhí)行g(shù)cc -c cHeader.c,會產(chǎn)生cHeader.o;
  • 2.然后執(zhí)行g(shù)++ -o C++ main.cpp cHeader.o
  • 3.執(zhí)行程序輸出:Header 100

注意: 在main.cpp文件中可以不用包含函數(shù)聲明的文件,即“extern "C"{#include"cHeader.h"}”,而直接改用extern "C" void log(int i)的形式。那main.cpp是如何找到C中的log函數(shù),并調(diào)用的呢?

那是因為首先通過gcc -c cHeader.c生成一個目標(biāo)文件cHeader.o,然后我們通過執(zhí)行g(shù)++ -o C++ main.cpp cHeader.o這個命令指明了需要鏈接的目標(biāo)文件cHeader.o。 main.cpp中只需要聲明哪些函數(shù)需要以C的形式調(diào)用,然后去目標(biāo)文件中查找即可。“.o”為目標(biāo)文件。類似Windows中的obj文件。

C中調(diào)用C++的代碼

C中調(diào)用C++中的代碼和前面的有所不同,首先在cppHeader.h中聲明一個_log_i方法。

#pragma once
extern "C" {
    void _log_i(int i);
}

在對應(yīng)的cppHeader.cpp中實現(xiàn)該方法:

#include "cppHeader.h"
#include &lt;stdio.h&gt;

void _log_i(int i) {
    printf("cppHeader:%d\n", i);
}

定義一個cMain.c文件調(diào)用_log_i方法:

extern void _log_i(int i);
int main() {
    _log_i(120);
}

注意點:

  • 1.如果直接在.c文件中include &ldquo;cppHeader.h”是會報錯的,因為cppHeader.h中包含了extern “C”,而將cppHeader.h包含進(jìn)來,會直接展開cppHeader.h內(nèi)容,而extern “C”在C語言中是不支持的,所以會報錯。
  • 2.在.c文件中不加extern void _log_i(int i)也會報錯

linux執(zhí)行上述文件的命令為:

(1)首先執(zhí)行命令:g++ cppHeader.cpp -fpic -shared -g -o cppHeader.so 該命令是將cppHeader.cpp編譯成動態(tài)連接庫,其中編譯參數(shù)的解釋如下:

  • -shared 該選項指定生成動態(tài)連接庫(讓連接器生成T類型的導(dǎo)出符號表,有時候也生成弱連接W類型的導(dǎo)出符號),不用該標(biāo)志外部程序無法連接。相當(dāng)于一個可執(zhí)行文件
  • -fPIC:表示編譯為位置獨立的代碼,不用此選項的話編譯后的代碼是位置相關(guān)的所以動態(tài)載入時是通過代碼拷貝的方式來滿足不同進(jìn)程的需要,而不能達(dá)到真正代碼段共享的目的。
  • -g:為調(diào)試

(2)然后再執(zhí)行命令:gcc cMain.c cppHeader.so -o cmain 該命令是編譯cMain.c文件,同時鏈接cppHeader.so文件,然后產(chǎn)生cmain的可執(zhí)行文件。

(3)最后執(zhí)行命令: ./cmain 來執(zhí)行該可執(zhí)行程序

結(jié)果:cppHeader:120

總結(jié)

本文主要講解了關(guān)于extern的三個知識點:

  • 1.extern的基礎(chǔ)用法:本模塊以及跨模塊的使用
  • 2.extern的在使用過程中的一些注意點,主要通過數(shù)組和指針的區(qū)別來講解。
  • 3.extern “C”在C++中的用法以及原理:講解了關(guān)于C和C++互相調(diào)用以及內(nèi)部實現(xiàn)機制。

參考

extern “C“ 用法詳細(xì)說明 extern關(guān)鍵字用法詳解 【C/C++】extern 的一些注意事項

以上就是C/C++ extern關(guān)鍵字用法示例全面解析的詳細(xì)內(nèi)容,更多關(guān)于C/C++ extern關(guān)鍵字用法的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C++實現(xiàn)LeetCode(135.分糖果問題)

    C++實現(xiàn)LeetCode(135.分糖果問題)

    這篇文章主要介紹了C++實現(xiàn)LeetCode(135.分糖果問題),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • C語言實現(xiàn)最小生成樹構(gòu)造算法

    C語言實現(xiàn)最小生成樹構(gòu)造算法

    這篇文章主要為大家詳細(xì)介紹了C語言實現(xiàn)最小生成樹構(gòu)造算法,利用Prim算法或kruskal算法求解,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-01-01
  • 基于C語言實現(xiàn)三子棋游戲的示例代碼

    基于C語言實現(xiàn)三子棋游戲的示例代碼

    這篇文章主要為大家詳細(xì)介紹了如何利用C語言數(shù)組實現(xiàn)簡單的三子棋游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • C語言實現(xiàn) 數(shù)據(jù)類型占多少字節(jié)指針占多少字節(jié)

    C語言實現(xiàn) 數(shù)據(jù)類型占多少字節(jié)指針占多少字節(jié)

    這篇文章主要介紹了 C語言 數(shù)據(jù)類型占多少字節(jié)指針占多少字節(jié)的實例代碼,代碼簡單易懂,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-09-09
  • C語言簡單實現(xiàn)快速排序

    C語言簡單實現(xiàn)快速排序

    快速排序是一種不穩(wěn)定排序,這篇文章主要為大家詳細(xì)介紹了C語言簡單實現(xiàn)快速排序,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-01-01
  • VS中PCL庫附加依賴項配置過程解析

    VS中PCL庫附加依賴項配置過程解析

    這篇文章主要介紹了VS中PCL庫附加依賴項配置,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-07-07
  • C語言實現(xiàn)計算器的兩種方法

    C語言實現(xiàn)計算器的兩種方法

    這篇文章主要為大家詳細(xì)介紹了C語言實現(xiàn)計算器的兩種方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • C++哈希應(yīng)用的位圖和布隆過濾器

    C++哈希應(yīng)用的位圖和布隆過濾器

    這篇文章主要介紹了C++哈希應(yīng)用的位圖和布隆過濾器的相關(guān)資料,文章內(nèi)容多以列舉試題的方式講解,感興趣的朋友可以參考下面文章內(nèi)容
    2021-09-09
  • C語言的基本語法詳解

    C語言的基本語法詳解

    本篇文章主要講解C語言 基本語法,這里提供簡單的示例和代碼來詳細(xì)講解C語言的基本語法,開始學(xué)習(xí)C語言的朋友可以看一下,希望能夠給你帶來幫助
    2021-09-09
  • 一起來了解一下C++的結(jié)構(gòu)體?struct

    一起來了解一下C++的結(jié)構(gòu)體?struct

    這篇文章主要為大家詳細(xì)介紹了C++的結(jié)構(gòu)體struct,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-02-02

最新評論