c和c混合編程
可以!
用C來做後台無非做兩件事情,一提高效率,二涉及一些底層的操作。
你可以先把C寫的那部分代碼編譯成一個DLL,然後在C#中調用這個DLL,C與C#在類型上基本相同,但也有一些區別。你可以到晚上搜一下,C#與C混合編程,或者C#與C++混合編程。
B. 最近在搞C\C++ 和匯編語言 的混合編程,如何講2者在編譯環境中連接起來。
詳細的官方資料見masm
programmer's
guide
中的第12章
混合語言編程,網上有pdf版本,但有一些版本的無法顯示圖片,好好的看一下吧。
----------------------------------------
混合編程允許你把微軟Basic、C、C++和FORTRAN的長處與匯編語言常式聯合起來。這些語言中的任何一種都可以調用MASM常式,你也可以在匯編程序里調用這些語言中的任何一種。這實際上使混合語言程序可以使用所有高級語言庫的常式。
MASM
6.1提供的混合語言特徵類似於高級語言里提供的特徵。例如,你可以使用INVOKE直接調用高級語言過程,匯編器為你處理參數傳遞的細節。你也可以使用H2INC把C頭文件翻譯為MASM的include文件,這在第20章的Environment
and
Tools里解釋。
MASM
6.1的混合語言特徵沒有廢棄舊的定義混合語言介面的方法。在大多數情形下,使用較早版本的MASM編寫的混合語言程序可以在MASM
6.1里正確地匯編和連接(為了解更多的信息,見附錄A)。
本章解釋了如何編寫高級語言模塊可以調用的匯編常式,MASM如何調用高級語言常式。你應該已經理解你希望聯合的語言,應該知道如何使用這些語言編寫、編譯和連接多模塊程序。
本章僅覆蓋了C、C++、Basic和FORTRAN的匯編語言介面,沒有覆蓋高級語言間的混合編程。此處的重點是微軟版本的C、C++、Basic和FORTRAN,但相同的原則適用於其他語言和編譯器。本章使用的許多技巧使用了第7章里的關於使用匯編語言編寫過程,以及第8章的多模塊編程的資料進行解釋。
C. 為什麼要C和匯編混合編程
依我的看法,上面兩位說的都不對:
一樓:匯編語言是低級語言直接往硬體的寄存器里寫入東西:
其實C語言和匯編語言都一樣,都會編譯成二進制文件機器語言燒錄到單片機中,所以沒有一樓所說的區別
二樓:在C中也不會有數據損失的,如果你定義好數據類型的話。
單片機中是將C編譯成匯編,然後根據匯編編譯成機器語言---可執行文件;
其實單片機中經常在C中嵌入匯編,主要是因為時間的關系,因為一條匯編語言執行的時間都是可以知道的,而C指令執行的時間是不可知的,因為C編譯器不一樣,編譯後的匯編也是不一樣的,如果用匯編就不會有這種情況。所以在一些精確延時的場合,要嵌入匯編
另外,C的可移植性較強,不同的單片機里,功能要求相同的可以直接拿去用
總之,匯編是程序員可以自己翻譯成機器語言的,所以單片機的運行是可以完全掌握的
D. c語言和匯編語言的混合編程方法主要有哪些
C語言在實際應用中,為了完成某種特定的功能,或需要縮短程序的運行時間,或需要對硬體進行直接操作,或需要利用操作系統的某些功能模塊,這時就會使用到匯編語言程序,即要採用C語言與匯編語言的混合編程技術實現。
C與匯編語言的混合編程方法,為C語言應用開發人員提供方便。匯編語言開發的程序代碼短、執行速度快,而C語言是應用廣泛的面向過程的開發語言。通過給出混合編程的方法、約定規則以及實現的具體步驟,說明了混合編程需要注意的問題,最後給出了相應的實例。
(4)c和c混合編程擴展閱讀:
匯編語言具有更高的機器相關性,更加便於記憶和書寫,但又同時保留了機器語言高速度和高效率的特點。匯編語言仍是面向機器的語言,很難從其代碼上理解程序設計意圖,設計出來的程序不易被移植,故不像其他大多數的高級計算機語言一樣被廣泛應用。所以在高級語言高度發展的今天,它通常被用在底層,通常是程序優化或硬體操作的場合。
E. 匯編語言和c/c++的混合編程通常有哪四種方式
1、在C和C++代碼中內聯匯編
2、使用C、C++程序調用匯編庫
3、反匯編C和C++代碼,在匯編碼上進行優化,最後編譯
4、匯編調用C庫
F. 什麼是C++和C的混合編程
取個例子給你說吧:很多人喜歡在C語言中用string,可實際上這個函數在c中是不存在的,他是屬於C++的,這就是一個簡單的混合編程;
簡而言之,混合編程是將不屬於自己語言用在自己的語言中。
而且混合編程一般都要在支持兩者的運行環境下運行才可以,就像VC++;
G. C/C++混合編程,在C程序中調用C++函數
上面的錯誤是 extern BOOL InsertLog( const char* szLog ); 已經在其他地方定義了。
Compiler Error C2732
linkage specification contradicts earlier specification for 'function'
The function is already declared with a different linkage specifier.
Possible cause
Include files with different linkage specifiers.
Change the extern statements so that the linkages agree.
你試著把 #include "proj.h"加到函數
extern "C" BOOL InsertLog( const char* szLog )
{
……
}試試。
如果還是不行,你試著把#include "proj.h" 文件中的 extern BOOL InsertLog( const char* szLog ); 改為 BOOL InsertLog( const char* szLog ); 試一試。
H. C和C++如何混合編程
在用C++的項目源碼中,經常會不可避免的會看到下面的代碼:
1
#ifdef __cplusplus
2
extern "C" {
3
#endif
4
5
/*...*/
6
7
#ifdef __cplusplus
8
}
9
#endif
它到底有什麼用呢,你知道嗎?而且這樣的問題經常會出現在面試or筆試中。下面我就從以下幾個方面來介紹它:
1、#ifdef _cplusplus/#endif _cplusplus及發散
2、extern "C"
2.1、extern關鍵字
2.2、"C"
2.3、小結extern "C"
3、C和C++互相調用 4、C和C++混合調用特別之處函數指針
3.1、C++的編譯和連接
3.2、C的編譯和連接
3.3、C++中調用C的代碼
3.4、C中調用C++的代碼
1、#ifdef _cplusplus/#endif _cplusplus及發散
在介紹extern "C"之前,我們來看下#ifdef
_cplusplus/#endif
_cplusplus的作用。很明顯#ifdef/#endif、#ifndef/#endif用於條件編譯,#ifdef
_cplusplus/#endif
_cplusplus——表示如果定義了宏_cplusplus,就執行#ifdef/#endif之間的語句,否則就不執行。
在這里為什麼需要#ifdef _cplusplus/#endif
_cplusplus呢?因為C語言中不支持extern "C"聲明,如果你明白extern
"C"的作用就知道在C中也沒有必要這樣做,這就是條件編譯的作用!在.c文件中包含了extern "C"時會出現編譯時錯誤。
既然說到了條件編譯,我就介紹它的一個重要應用——避免重復包含頭文件。還記得騰訊筆試就考過這個題目,給出類似下面的代碼(下面是我最近在研究的一個開源web伺服器——Mongoose的頭文件mongoose.h中的一段代碼):
01
#ifndef MONGOOSE_HEADER_INCLUDED
02
#define MONGOOSE_HEADER_INCLUDED
03
04
#ifdef __cplusplus
05
extern "C" {
06
#endif /* __cplusplus */
07
08
/*.................................
09
* do something here
10
*.................................
11
*/
12
13
#ifdef __cplusplus
14
}
15
#endif /* __cplusplus */
16
17
#endif /* MONGOOSE_HEADER_INCLUDED */
然後叫你說明上面宏#ifndef/#endif的作用?為了解釋一個問題,我們先來看兩個事實:
這個頭文件mongoose.h可能在項目中被多個源文件包含(#include
"mongoose.h"),而對於一個大型項目來說,這些冗餘可能導致錯誤,因為一個頭文件包含類定義或inline函數,在一個源文件中mongoose.h可能會被#include兩次(如,a.h頭文件包含了mongoose.h,而在b.c文件中#include
a.h和mongoose.h)——這就會出錯(在同一個源文件中一個結構體、類等被定義了兩次)。
從邏輯觀點和減少編譯時間上,都要求去除這些冗餘。然而讓程序員去分析和去掉這些冗餘,不僅枯燥且不太實際,最重要的是有時候又需要這種冗餘來保證各個模塊的獨立。
為了解決這個問題,上面代碼中的
#ifndef MONGOOSE_HEADER_INCLUDED
#define MONGOOSE_HEADER_INCLUDED
/*……………………………*/
#endif /* MONGOOSE_HEADER_INCLUDED */
就起作用了。如果定義了MONGOOSE_HEADER_INCLUDED,#ifndef/#endif之間的內容就被忽略掉。因此,編譯時第一次看到mongoose.h頭文件,它的內容會被讀取且給定MONGOOSE_HEADER_INCLUDED一個值。之後再次看到mongoose.h頭文件時,MONGOOSE_HEADER_INCLUDED就已經定義了,mongoose.h的內容就不會再次被讀取了。
2、extern "C"
首先從字面上分析extern "C",它由兩部分組成——extern關鍵字、"C"。下面我就從這兩個方面來解讀extern "C"的含義。
2.1、extern關鍵字
在一個項目中必須保證函數、變數、枚舉等在所有的源文件中保持一致,除非你指定定義為局部的。首先來一個例子:
1
//file1.c:
2
int x=1;
3
int f(){do something here}
4
//file2.c:
5
extern int x;
6
int f();
7
void g(){x=f();}
在file2.c中g()使用的x和f()是定義在file1.c中的。extern關鍵字表明file2.c中x,僅僅是一個變數的聲明,其並不是在定義變數x,並未為x分配內存空間。變數x在所有模塊中作為一種全局變數只能被定義一次,否則會出現連接錯誤。但是可以聲明多次,且聲明必須保證類型一致,如:
1
//file1.c:
2
int x=1;
3
int b=1;
4
extern c;
5
//file2.c:
6
int x;// x equals to default of int type 0
7
int f();
8
extern double b;
9
extern int c;
在這段代碼中存在著這樣的三個錯誤:
x被定義了兩次
b兩次被聲明為不同的類型
c被聲明了兩次,但卻沒有定義
回到extern關鍵字,extern是C/C++語言中表明函數和全局變數作用范圍(可見性)的關鍵字,該關鍵字告訴編譯器,其聲明的函數和變數可以在本模塊或其它模塊中使用。通常,在模塊的頭文件中對本模塊提供給其它模塊引用的函數和全局變數以關鍵字extern聲明。例如,如果模塊B欲引用該模塊A中定義的全局變數和函數時只需包含模塊A的頭文件即可。這樣,模塊B中調用模塊A中的函數時,在編譯階段,模塊B雖然找不到該函數,但是並不會報錯;它會在連接階段中從模塊A編譯生成的目標代碼中找到此函數。
與extern對應的關鍵字是 static,被它修飾的全局變數和函數只能在本模塊中使用。因此,一個函數或變數只可能被本模塊使用時,其不可能被extern 「C」修飾。
2.2、"C"
典型的,一個C++程序包含其它語言編寫的部分代碼。類似的,C++編寫的代碼片段可能被使用在其它語言編寫的代碼中。不同語言編寫的代碼互相調用是困難的,甚至是同一種編寫的代碼但不同的編譯器編譯的代碼。例如,不同語言和同種語言的不同實現可能會在注冊變數保持參數和參數在棧上的布局,這個方面不一樣。
為了使它們遵守統一規則,可以使用extern指定一個編譯和連接規約。例如,聲明C和C++標准庫函數strcyp(),並指定它應該根據C的編譯和連接規約來鏈接:
1
extern "C" char* strcpy(char*,const char*);
注意它與下面的聲明的不同之處:
1
extern char* strcpy(char*,const char*);
下面的這個聲明僅表示在連接的時候調用strcpy()。
extern "C"指令非常有用,因為C和C++的近親關系。注意:extern "C"指令中的C,表示的一種編譯和連接規約,而不是一種語言。C表示符合C語言的編譯和連接規約的任何語言,如Fortran、assembler等。
還有要說明的是,extern "C"指令僅指定編譯和連接規約,但不影響語義。例如在函數聲明中,指定了extern "C",仍然要遵守C++的類型檢測、參數轉換規則。
再看下面的一個例子,為了聲明一個變數而不是定義一個變數,你必須在聲明時指定extern關鍵字,但是當你又加上了"C",它不會改變語義,但是會改變它的編譯和連接方式。
如果你有很多語言要加上extern "C",你可以將它們放到extern "C"{ }中。
2.3、小結extern "C"
通過上面兩節的分析,我們知道extern "C"的真實目的是實現類C和C++的混合編程。在C++源文件中的語句前面加上extern "C",表明它按照類C的編譯和連接規約來編譯和連接,而不是C++的編譯的連接規約。這樣在類C的代碼中就可以調用C++的函數or變數等。(註:我在這里所說的類C,代表的是跟C語言的編譯和連接方式一致的所有語言)
3、C和C++互相調用
我們既然知道extern "C"是實現的類C和C++的混合編程。下面我們就分別介紹如何在C++中調用C的代碼、C中調用C++的代碼。首先要明白C和C++互相調用,你得知道它們之間的編譯和連接差異,及如何利用extern "C"來實現相互調用。
3.1、C++的編譯和連接
C++是一個面向對象語言(雖不是純粹的面向對象語言),它支持函數的重載,重載這個特性給我們帶來了很大的便利。為了支持函數重載的這個特性,C++編譯器實際上將下面這些重載函數:
1
void print(int i);
2
void print(char c);
3
void print(float f);
4
void print(char* s);
編譯為:
1
_print_int
2
_print_char
3
_print_float
4
_pirnt_string
這樣的函數名,來唯一標識每個函數。註:不同的編譯器實現可能不一樣,但是都是利用這種機制。所以當連接是調用print(3)時,它會去查找_print_int(3)這樣的函數。下面說個題外話,正是因為這點,重載被認為不是多態,多態是運行時動態綁定(「一種介面多種實現」),如果硬要認為重載是多態,它頂多是編譯時「多態」。
C++中的變數,編譯也類似,如全局變數可能編譯g_xx,類變數編譯為c_xx等。連接是也是按照這種機制去查找相應的變數。
3.2、C的編譯和連接
C語言中並沒有重載和類這些特性,故並不像C++那樣print(int
i),會被編譯為_print_int,而是直接編譯為_print等。因此如果直接在C++中調用C的函數會失敗,因為連接是調用C中的print(3)時,它會去找_print_int(3)。因此extern
"C"的作用就體現出來了。
3.3、C++中調用C的代碼
假設一個C的頭文件cHeader.h中包含一個函數print(int i),為了在C++中能夠調用它,必須要加上extern關鍵字(原因在extern關鍵字那節已經介紹)。它的代碼如下:
1
#ifndef C_HEADER
2
#define C_HEADER
3
4
extern void print(int i);
5
6
#endif C_HEADER
相對應的實現文件為cHeader.c的代碼為:
1
#include <stdio.h>
2
#include "cHeader.h"
3
void print(int i)
4
{
5
printf("cHeader %d\n",i);
6
}
現在C++的代碼文件C++.cpp中引用C中的print(int i)函數:
1
extern "C"{
2
#include "cHeader.h"
3
}
4
5
int main(int argc,char** argv)
6
{
7
print(3);
8
return 0;
9
}
執行程序輸出:
3.4、C中調用C++的代碼
現在換成在C中調用C++的代碼,這與在C++中調用C的代碼有所不同。如下在cppHeader.h頭文件中定義了下面的代碼:
1
#ifndef CPP_HEADER
2
#define CPP_HEADER
3
4
extern "C" void print(int i);
5
6
#endif CPP_HEADER
相應的實現文件cppHeader.cpp文件中代碼如下:
1
#include "cppHeader.h"
2
3
#include <iostream>
4
using namespace std;
5
void print(int i)
6
{
7
cout<<"cppHeader "<<i<<endl;
8
}
在C的代碼文件c.c中調用print函數:
1
extern void print(int i);
2
int main(int argc,char** argv)
3
{
4
print(3);
5
return 0;
6
}
注意在C的代碼文件中直接#include "cppHeader.h"頭文件,編譯出錯。而且如果不加extern int print(int i)編譯也會出錯。
4、C和C++混合調用特別之處函數指針
當我們C和C++混合編程時,有時候會用一種語言定義函數指針,而在應用中將函數指針指向另一中語言定義的函數。如果C和C++共享同一中編譯和連接、函數調用機制,這樣做是可以的。然而,這樣的通用機制,通常不然假定它存在,因此我們必須小心地確保函數以期望的方式調用。
而且當指定一個函數指針的編譯和連接方式時,函數的所有類型,包括函數名、函數引入的變數也按照指定的方式編譯和連接。如下例:
01
typedef int (*FT) (const void* ,const void*);//style of C++
02
03
extern "C"{
04
typedef int (*CFT) (const void*,const void*);//style of C
05
void qsort(void* p,size_t n,size_t sz,CFT cmp);//style of C
06
}
07
08
void isort(void* p,size_t n,size_t sz,FT cmp);//style of C++
09
void xsort(void* p,size_t n,size_t sz,CFT cmp);//style of C
10
11
//style of C
12
extern "C" void ysort(void* p,size_t n,size_t sz,FT cmp);
13
14
int compare(const void*,const void*);//style of C++
15
extern "C" ccomp(const void*,const void*);//style of C
16
17
void f(char* v,int sz)
18
{
19
//error,as qsort is style of C
20
//but compare is style of C++
21
qsort(v,sz,1,&compare);
22
qsort(v,sz,1,&ccomp);//ok
23
24
isort(v,sz,1,&compare);//ok
25
//error,as isort is style of C++
26
//but ccomp is style of C
27
isort(v,sz,1,&ccopm);
28
}
注意:typedef int (*FT) (const void* ,const void*),表示定義了一個函數指針的別名FT,這種函數指針指向的函數有這樣的特徵:返回值為int型、有兩個參數,參數類型可以為任意類型的指針(因為為void*)。
最典型的函數指針的別名的例子是,信號處理函數signal,它的定義如下:
1
typedef void (*HANDLER)(int);
2
HANDLER signal(int ,HANDLER);
上面的代碼定義了信函處理函數signal,它的返回值類型為HANDLER,有兩個參數分別為int、HANDLER。 這樣避免了要這樣定義signal函數:
1
void (*signal (int ,void(*)(int) ))(int)
比較之後可以明顯的體會到typedef的好處。
I. 如何解決C和C++互相調用的問題
在實際工作中可能經常要進行C和C++的混合編程,C++調用C語言的代碼通常都比較容易,但也有一些細節需要注意。C要調用C++的代碼就略為麻煩一些,因為C不支持面向對象的特徵。 1,首先我們來看一下C++調用C語言的代碼。要讓你的C代碼既能被C代碼又能被C++調用雖說容易,但是還是有需要注意的地方。現有三個文件分別如下:[cpp]#ifndef TESTC_H#defineTESTC_H#ifdef__cplusplus //2個下劃線extern"C"{#endifintadd(inta, intb);#ifdef__cplusplus}#endif#endif[cpp]#include "TestC.h"intadd(inta, intb){return(a+b);}[cpp]#include#include"TestC.h"intmain(){printf("add=%d\n" ,add(2,5));return0;}說明: file TestC.h是C的頭文件,file TestC.c是其實現文件,file TestCpp.cpp是調用C函數的C++文件。文件TestC.h中的TESTC_H定義是為了頭文件保護,」#ifdef__cplusplus 」這個不能缺少,你可以去查看C的標准庫頭文件中都有這個,如」stdio.h」。有了這個宏編譯器就知道現在是C還是C++在調用它。 C編譯器編譯後在符號庫中的名字為_add,而C++編譯器則會產生像_add_int_int之類的名字。C++正是依靠這種機制實現了函數的重載。 extern關鍵字表示將函數或變數聲明為全局類型,與之相對應的是static。static限定函數或變數的作用域為本文件。extern還有一個作用就是與」C」連在一起使用,即extern「C」通知編譯器將extern 「C」所包含的代碼按照C的方式編譯和鏈接。 intb){return(a+b);}}; 將C++類封裝為C函數的文件(為了簡略也將聲明和實現放在了同一個文件中)如下:[cpp]#include"TestClass.h"extern"C"intadd_cpp(inta, intb);intadd_cpp(inta, intb){ADDs;return s.add(a,b) ;} 實際調用C++代碼的C文件如下:[cpp]#includeexternintadd_cpp(inta, intb);intmain(){printf("add_cpp=%d\n" ,add_cpp(2,5));return0;} 上面的過程很清晰,就是用一個函數將C++類的使用封裝起來,然後將它外部聲明為C函數就可以了。文件TestClass.h定義並實現了一個類,該類只有一個add方法。文件TestCpp.cpp定義並實現了一個函數add_cpp,函數中定義了一個HJH類對象並調用了該對象的add方法。然後將add_cpp函數進行外部聲明為C。 TestC.c文件中為了使用add_cpp函數,也需要進行外部聲明。這是為了通知編譯器說明這個函數是在其他文件中實現(注意在C文件中的extern後面不可加」C」 )。
J. 在vs2008下,C/C++混合編程,為何會出現以下的錯誤
右鍵你的c文件,查看屬性,
c\C++,高級,看看,「編譯為」,選擇c代碼