1. 程式人生 > >extern ”C"的使用

extern ”C"的使用

本文分析extern “C”的使用方法;介紹C++和C程式碼相互呼叫的方式。

連結指示extern "C"

          extern "C" 包含雙重含義,從字面上即可得到:首先,被它修飾的目標是“extern”的;其次,被它修飾的目標是“C”的。被extern "C"限定的函式或變數是extern型別的。

          externC/C++語言中表明函式和全域性變數作用範圍(可見性)的關鍵字,該關鍵字告訴編譯器,其宣告的函式和變數可以在本模組或其它模組中使用。記住,語句:

  1. externint a;  //宣告,未分配空間

僅僅是一個變數的宣告,其並不是在定義變數a,並未為a分配記憶體空間。變數

a在所有模組中作為一種全域性變數只能被定義一次,否則會出現連線錯誤。

但是注意,如果將上述語句賦值的話,那麼它就是定義了:

  1. externint a = 2;    //定義。只有定義時才可以初始化;若宣告有初始化,則它就是定義了(即使有extern)

         通常,在模組的標頭檔案對本模組供給其他模組使用的函式和全域性變數以關鍵字extern宣告。例如,模組B欲引用模組A中的全域性變數和函式時,只需要包含A的標頭檔案即可。這樣,模組B中呼叫A模組的函式時,在編譯階段,B找不到該函式定義但是不會報錯,會在連線階段中從模組A編譯生成的目的碼中找到該函式。

        例如,在下面的“C呼叫C++函式”一節中,在cpptest.h標頭檔案中聲明瞭一個extern int test變數,test變數的定義下載cpptest.cpp檔案中,那麼在c_use_c++.c中就可以通過包含cpptest.h標頭檔案來引用test變數。雖然.cpp檔案中將test賦值為2但是在main函式中將test再次賦值為1,因此,最後在main函式中test的兩次輸出均為1。

        與extern關鍵字對應的是static,它修飾的函式和變數只能在本模組中使用。因此,如果函式或變數只允許在本模組中使用,那麼不能用extern “C"修飾。

注意幾點

(1)連結指示extern "C"中的“C"代表的並不是C語言,而是用extern ”C“來宣告非C++函式;實際上Fortran和組合語言也常常使用,因為它們也正好符合C實現的約定。支援什麼語言由編譯器而定,C++保證支援的唯一語言是C

(2)extern ”C“不能出現在類定義或函式定義的內部,必須出現在函式的第一次宣告上。

(3)連結指示的兩種形式:單個的和複合的。如:

  1. //單個的形式
  2. extern"C"void test(
    int a);  
  3. //複合形式
  4. extern"C" {  
  5. void test(int a);  
  6. int fun(int a, double b);  
  7. }  

(4)連結指示和標頭檔案

可以將多重宣告形式應用於整個標頭檔案,如C++的cstring標頭檔案可以像這樣:

  1. extern"C" {  
  2.       #include <string.h>
  3. }  
如果寫成上面的形式,那麼string.h標頭檔案中的所有普通函式都假定為用連結指示的語言編寫的。連線指示可以巢狀,因此,如果標頭檔案中包含了帶連結指示的函式,該好函式的連結不受影響。

(5)通過連線指示可以讓C++使用C的函式,也可以讓C使用C++的函式。這點之後的”C和C++的相互呼叫“會介紹。

(6)當C++呼叫其他語言的函式時,C++必須宣告用其他語言編寫的函式的名字。編譯器按照處理普通C++函式的方式檢查對外部語言函式的呼叫,但是,編譯器一般必須產生不同的程式碼來呼叫其他語言編寫的函式。C++使用連結指示指出任意非C++函式所使用的語言。

(7)為什麼C++中呼叫被C編譯器編譯後的函式,要加extern ”C"?

         C不支援過載函式,因此C++中的過載函式中僅能只有一個函式宣告為extern "C",否則會出錯。extern "C"解決名字匹配問題。例如對於void fun(int a)這樣的函式,為了支援過載機制,C++將函式的名字編譯為類似_fun_int或_xxx_funDxxx這樣的形式,而C語言則一般將函式編譯為類似_fun這樣的形式。那麼,對於用C編譯器編譯成的庫,用C++直接連結勢必會出現不能識別符號的問題。extern "C" 的作用就是讓編譯器知道要以C語言的方式編譯和連線封裝函式。

C和C++的相互呼叫

C++呼叫C函式

首先定義一個C的檔案及相應的標頭檔案,將其編譯生成C的動態庫,然後讓C++來呼叫該C的庫。

  1. //ctest.c
  2. #include "ctest.h"
  3. void test(int a, double b) {  
  4.   printf("a: %d\n", a);  
  5.   printf("b: %lf\n", b);  
  6. }  
  1. //ctest.h
  2. #ifndef CTEST_H
  3. #define CTEST_H
  4. #include <stdio.h>
  5. void test(intdouble);  
  6. #endif
編譯生成C動態庫:gcc --shared -o libtest_c++_use_c.so ctest.c

  1. //c++_use_c.cpp
  2. extern"C"void test(intdouble);  
  3. //extern void test(int, double);
  4. int main() {  
  5.   test(2, 1.4);  
  6.   return 0;  
  7. }  
使用上邊生成的動態庫libtest_c++_use_c.so來編譯該C++檔案:g++ -o c++_use_c c++_use_c.cpp -L /home/yang -ltest_c++_use_c

執行:./c++_use_c

執行的結果如下圖所示。


分析上述程式:

         在上面的程式中,c++_use_c.cpp是一個C++程式,它呼叫了C函式test。按照之前的分析,在c++_use_c.cpp中要使用extern “C”來宣告非C++函式,呼叫C語言編寫的函式。c++_use_c.cpp如果沒有extern "C"連結指示,而僅僅僅換成註釋中所示的普通的函式宣告,編譯該檔案會出錯(即使註釋處有extern關鍵字也會出錯)如下圖所示。因為g++編譯器按照C++的方式來在main函式中呼叫test函式,這樣將沒辦法找到C++方式的test函式,因為test函式時gcc編譯成的C函式的方式。


C呼叫C++函式

         簡單思考下:C語言先於C++出現,C++是在C的基礎上發展來的。因此,可以想象,C並沒有呼叫C++的機制,因此要實現C呼叫C++函式通過對要呼叫的C++函式進行處理

  1. //cpptest.cpp
  2. #include "cpptest.h"
  3. #include <stdio.h>
  4. #include <iostream>
  5. usingnamespace std;  
  6. /* 
  7. #ifdef __cplusplus 
  8. extern "C" { 
  9. #endif 
  10. */
  11. int test = 2;  
  12. void fun(int a) {  
  13.     cout << "test in fun: "  << test << endl;  
  14.     cout << "a: " << a << endl;  
  15.         printf("test in fun: %d\n", test);  
  16.         printf("a: %d\n", a);  
  17. }  
  18. /* 
  19. #ifdef __cplusplus 
  20. } 
  21. #endif 
  22. */
  1. //cpptest.h
  2. #ifndef CPP_TEST_H
  3. #define CPP_TEST_H
  4. #ifdef __cplusplus
  5. extern"C" {  
  6. #endif
  7. void fun(int);  
  8. //寫成這樣也會出錯:extern "C" void fun(int);
  9. 相關推薦

    extern C的作用具體解釋

    archive 連接方式 一道 org 深入 key ext vxworks 局部變量 轉載於:http://www.cnblogs.com/rollenholt/archive/2012/03/20/2409046.html 1.引言   C+&#

    extern C的作用

    .net .com sdn extern c question https details 處理 c++編譯 #ifdef __cplusplus extern "C" { #endif //一段代碼 #ifdef __cplusplus } #endif https://

    extern c

    鏈接方式 全局變量 似的 設計 試題 main 編譯器 extern c 引用 extern "C"的主要作用就是為了能夠正確實現C++代碼調用其他C語言代碼。加上extern "C"後,會指示編譯器這部分代碼按C語言的進行編譯,而不是C++的。由於C++支持函數重載,因

    C++中externC”含義深層探索

    之前做很多專案,都用到了extern “C”,這裡整理一下extern “C”的作用。 本文轉自:http://www.cppblog.com/Macaulish/archive/2008/06/17/53689.html 1.引言   C++語言的建立初衷是“a better C”,但

    externC” 在C/C++中的使用

    1 : 問題定義   在研究作業系統原始碼或者在嵌入式系統中編寫程式時,經常會發現下面這種用法: [cpp] view plain copy    #ifndef __OTHER_FILE_C_H__-----

    C/C++混合程式設計--externC” 使用方法詳解

    1. 首先要明白: 被extern “C”修飾的變數和函式是按照C語言方式編譯和連結的 (1) 首先看看C++中對類似C的函式是怎樣編譯的。 C++支援函式過載,而過程式語言C則不支援。函式被C++編譯後在符號庫中的名字與C語言的不同。例如,假設某個函式的原型為: void foo( i

    C/C++混合程式設計 #ifdef __cplusplus extern "C" {...}

    C用gcc方式編譯;C++用g++方式編譯。 C/C++混合程式設計需要關鍵字extern。 c++呼叫c比較簡單,只需要extern; ||  而c呼叫c++則需要考慮c++的函式過載等功能,需要使用 #ifdef __cplusplus extern "C" {...

    DLL編寫中externC”和__stdcall的作用

    動態連結庫的使用有兩種方式,一種是顯式呼叫。一種是隱式呼叫。 (1)       顯式呼叫:使用LoadLibrary載入動態連結庫、使用GetProcAddress獲取某函式地址。 (2)       隱式呼叫:可以使用#pragma comment(lib, “XX.

    C語言呼叫C++中的函式,extern "C"的含義

    C++編譯器在將cpp檔案編譯成庫時,匯出的函式名會改變,成員函式會通過加一些元素變成全域性函式,如果這時候我們需要用C語言呼叫C++的函式, 就有了一個問題,那就是不知道C++庫中匯出的函式名,這是由編譯器決定的,這個時候就需要用到extern關鍵字。例子: test.c

    extern "C" 用法理解與總結

    被extern "C"修飾的變數和函式是按照C語言方式進行編譯和連結的 舉個例子: 1.moduleA、moduleB兩個模組 2.B呼叫A中的程式碼 3.其中A是用C語言實現的,而B是利用C++實現的 //moduleA標頭檔案:moduleA.h #ifnde

    extern "C"的使用詳解(轉)

      extern "C"的主要作用就是為了能夠正確實現C++程式碼呼叫其他C語言程式碼。加上extern "C"後,會指示編譯器這部分程式碼按C語言的進行編譯,而不是C++的。由於C++支援函式過載,因此編譯器編譯函式的過程中會將函式的引數型別也加到編譯後的程式碼中,而不僅僅

    extern C 淺析

    one.h檔案 #pragma once #include<stdio.h> void show(); one.c檔案 #include"one.h" void show() { printf("我是C語言中實現的show函式\n"); } m

    C/C++基礎----特殊工具和技術 (過載new和delete,RTT,限定作用域的列舉型別,類成員指標,巢狀類,區域性類,volatile,連結指示 externC”)

    過載new和delete 1呼叫operator new( 或new[])標準庫函式分配足夠大的、原始的、未命名的記憶體空間以便儲存特定型別的物件 2編譯器執行相應地建構函式以構造這些物件,併為其傳入初始值 3返回一個指向該物件的指標 可以在全域性作用域定義operator new,也可以定義為成員函式

    ffmpeg連結錯誤:關於C++ extern "C"

    http://www.360doc.com/content/13/0502/17/9192936_282472350.shtml 在編譯一個ffmepg AAC解碼測試程式時,遇到了如下錯誤輸出: 1>main.obj : error LNK2001: 無法

    C++專案中的extern "C" {}

    作者:吳秦 出處:http://www.cnblogs.com/skynet/ 引言 在用C++的專案原始碼中,經常會不可避免的會看到下面的程式碼: #ifdef __cplusplus extern"C" { #endif /*...*/ #ifdef __cplusplus } #endi

    DLL進一步講解:extern C & __declspec(dllexport)

    模組定義 (.def) 檔案是包含一個或多個描述各種 DLL 屬性的 Module 語句的文字檔案。 1、二者的目的都是將公共符號匯入到應用程式中或從 DLL 匯出函式。 2、新增 __declspec(dllexport)是為了提供不使用.def檔案從 .EXE 或 .DLL 匯出函式的簡單方法。 3、如果

    c呼叫c++函式,為什麼要加extern c

    首先,作為extern是C/C++語言中表明函式和全域性變數作用範圍(可見性)的關鍵字,該關鍵字告訴編譯器,其宣告的函式和變數可以在本模組或其它模組中使用。 通常,在模組的標頭檔案中對本模組提供給其它模組引用的函式和全域性變數以關鍵字extern宣告。例如,如果模組B欲引

    extern "C" __declspec(dllexport)

    模組定義 (.def) 檔案是包含一個或多個描述各種 DLL 屬性的 Module 語句的文字檔案。 1、二者的目的都是將公共符號匯入到應用程式中或從 DLL 匯出函式。 2、新增 __declspec(dllexport)是為了提供不使用.def檔案從 .EXE 或 .DLL 匯出函式的簡單方法。 3、如果

    externC"的使用

    本文分析extern “C”的使用方法;介紹C++和C程式碼相互呼叫的方式。連結指示extern "C"          extern "C" 包含雙重含義,從字面上即可得到:首先,被它修飾的目標是“extern”的;其次,被它修飾的目標是“C”的。被extern "C"限

    ios 開發使用 extern "C" __declspec(dllimport) 導致 unknown type name "__declspec"

    iOS 開發匯入c++ 檔案 使用extern "C" __declspec(dllimport) 導致 unknown type name "__declspec" 位元組方法,刪除這個部分,ios不需要這個部分