當前位置:首頁 » 編程軟體 » 混合式編程

混合式編程

發布時間: 2022-07-31 23:19:51

⑴ 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的好處。

⑵ 單片機C語言與匯編語言混合編程有哪幾種方式通常採用什麼方式

C語言具簡潔、靈活的特點以及豐富的庫函數和功能強大的調試手段,適用面非常廣泛。但在實際應用中,為了完成某種特定的功能,或需要縮短程序的運行時間,或需要對硬體進行直接操作,或需要利用操作系統的某些功能模塊,這時就會使用到匯編語言程序,即要採用C語言與匯編語言的混合編程技術實現。通過研究與分析Turbo
C與匯編語言的混合編程方法,為C語言應用開發人員提供方便。

⑶ c語言和匯編語言的混合編程方法主要有哪些

C語言在實際應用中,為了完成某種特定的功能,或需要縮短程序的運行時間,或需要對硬體進行直接操作,或需要利用操作系統的某些功能模塊,這時就會使用到匯編語言程序,即要採用C語言與匯編語言的混合編程技術實現。

C與匯編語言的混合編程方法,為C語言應用開發人員提供方便。匯編語言開發的程序代碼短、執行速度快,而C語言是應用廣泛的面向過程的開發語言。通過給出混合編程的方法、約定規則以及實現的具體步驟,說明了混合編程需要注意的問題,最後給出了相應的實例。

(3)混合式編程擴展閱讀:

匯編語言具有更高的機器相關性,更加便於記憶和書寫,但又同時保留了機器語言高速度和高效率的特點。匯編語言仍是面向機器的語言,很難從其代碼上理解程序設計意圖,設計出來的程序不易被移植,故不像其他大多數的高級計算機語言一樣被廣泛應用。所以在高級語言高度發展的今天,它通常被用在底層,通常是程序優化或硬體操作的場合。

⑷ 如何理解高級語言和匯編語言混合編程的

混合語言編程有:(1)整體模式;(2)非整體模式。

(1)整體模式:主程序為x語言,子程序或函數中的一部分或全部為y語言,最後通過鏈接程序封裝在一起形成一個exe文件。

(2)非整體模式:主程序為x語言,部分程序為y語言,主、子程序均獨立的生成exe文件,但在主程序中可調用其它的exe文件。參數傳遞通過命令行參數、返回碼 或者數據文件。這種方式的混合編程相對就簡單一些!

⑸ 多語言混合編程

起始所有程序都是一樣的,最終都是機器碼,只是在編寫時使用的語言不同(編程語言都是程序的抽象,為了編程方便,本身並不是可運行的程序,最終必須編譯成機器碼才能運行,不同語言只是不同人編的,用的語法不同),你寫的源文件無論是任何語言寫的,最終編譯的結果都是機器碼。 函數調用在機器碼就是很簡單的一步,將參數表要求的參數值放入堆棧(順序有約定),然後使用 jmp 指令跳轉到要調用的函數的函數地址即可,別的程序不管你怎麼實現,只要你告訴我參數表,和函數地址就能調用,所有程序最終都是機器碼,自然也符合這個規則。。。 所以實現互調,只要將對方的介面程序文件映射到自己的進程中,然後預先知道他的參數表,得到他的介面函數地址,將參數放入堆棧,然後跳轉到函數地址, 這樣你就實現調用。。。。 winodws提供了一個文件類型叫做.dll 動態鏈接庫,如果你希望讓其他程序調用,只用將文件編譯成dll即可,他就是一個程序文件,純機器碼,可以讓任何程序調用。。。。
具體實現方法,通過loadliabroray("xxxxx\xxx.dll"),將該文件映射到進程,getprocaddress("函數名"),得到他的函數地址,假設你已經知道這個函數格式為 int func(int,int,char),你就定義一個該類型的函數指針 ,將getprocaddress("函數名")的地址給這個函數指針,按C語言格式調用即可,很簡單的,這些都是操作系統的功勞,如果你學學windows系統編程,就知道了。。。
還有一種方式是,把另一個程序當做一個伺服器程序,通過約定的數據來間接調用。。。。比如有個字元串,叫「吃飯」,你只要將這個「吃飯」這兩個字發給另一個程序(操作系統提供了一個叫管道的內核對象,通過它,你可以給也使用該管道的程序發數據),他實現編了程序知道這是要干什麼,然後就自己執行。。。

⑹ C51語言的混合編程

C51編譯器能對C語言源程序進行高效率的編譯,生成高效簡潔的代碼,在絕大多數場合採用C語言編程即可完成預期的目的。但有時為了編程直觀或某些特殊地址的處理,還須採用一定的匯編語言編程。而在另一些場合,出於某種目的,匯編語言也可調用C語言。在這種混合編程中,關鍵是參數的傳遞和函數的返回值。它們必須有完整的約定,否則數據的交換就可能出錯,例 C語言程序與匯編語言程序的調用,其子程序如下:
PUBLIC AD ;入口地址
SEG_AD SEGMENT CODE;程序段
RSEG SEG_AD
USING 0
AD: MOV R6,#00
MOV R7,#00
SETB P1.1
ACALL DELAY
CLR P1.1
ACALL DELAY
MOV R0,#10
RR0: SETB P1.2
NOP
CLR P1.2
DJNZ R0,RR0
ACALL DELAY
MOV 30H,R6 ;A/D轉換的高
;兩位保存在R6中
ACALL CIR
MOV R6,30H
SETB P1.2
NOP
CLR P1.2
MOV 30H,R6
ACALL CIR
MOV R6,30H
MOV R0,#8 ;A/D轉換的低
;8位保存在R7中
RR2: SETB P1.2
NOP
CLR P1.2
MOV 30H,R7
ACALL CIR
MOV R7,30H
DJNZ R0,RR2
RET
CIR: CLR C
MOV C,P1.0
MOV A,30H
RLC A
MOV 30H,A
RET
END
在以上程序中,函數的返回值為一無符號整型數,根據調用規則,返回值的高位必須在R6中,低位在R7中,這樣才可保證數據的傳遞不出錯。另外,在調用過程中,必須注意寄存器的入棧。這樣在以後用到A/D轉換時,在C語言中調用匯編語言子程序AD()即可。

⑺ 數控機床混合編程

那是思維模式不一樣, 我學數控機床,機床運動從來不愛看刀具,就看導軌運動,並且以相對測量方式對刀時想是正是負的. 就是習慣問題,無論如何做對就可以了.

⑻ HTML5混合式開發究竟有哪些優勢呢

一、 四個月就擁有兩年以上的項目經驗
採用全真商業項目教學,學習同時積攢經驗,學習中參與名企項目開發設計,模擬公司項目流程,以實現知名網站/APP前端為檢驗學習成果的標准,積累大牛級項目經驗!根據產品需求,分析並給出完美的頁面前端結構解決方案。
二、了解UI/Android/iOS,和工程師高效溝通
學習中,自帶項目實訓屬性,Web前端開發學員可與UI、Android和iOS開發人員進行溝通,一起進行實戰演練,分組做項目,價值和收獲倍增!與設計師和移動開發工程師配合,利用HTML5/CSS3/JavaScript等Web技術進行產品的界面開發;了解APP製作項目全流程,掌控前端頁面設計趨勢,製作的頁面符合新技術和審美要求。
三、 PC+移動端+混合應用,學會輕盈高效的代碼
培訓學習中,有行業大牛教小清新的代碼,簡短精悍又高效,出錯率低。學習移動網站和PC網站的前端構建、交互設計與實現;學習各種類型網頁前端頁面開發製作和維護;學習良好的代碼習慣,要求結構清晰,命名規范,邏輯性強,代碼冗餘率低。會這招,老闆就要定了!
四、 全面掌握頁面兼容性和優化
在培訓學習,教高效解決各種平台瀏覽器的兼容性問題。包括在各種手機解析度、PAD平台上的兼容和性能優化。學習優化前端體驗和頁面響應速度,優化代碼並保持良好兼容性,提升Web界面的友好和易用。跨瀏覽器開發經驗,具備獨立開發JavaScript經驗,清楚地了解不同瀏覽器上的兼容情況、渲染原理和存在的Bug,確保網站能在IE、Firefox、360、Android、iOS手機瀏覽器等主流瀏覽器正常瀏覽。
五、 課程方向覆蓋企業前端技術崗位需求
如今,武漢前端開發工程師的職責,不是只有切圖、製作網頁這么簡單,學習課程必須完全覆蓋武漢行業內崗位需求,才能輕松勝任武漢WEB前端/移動端/混合應用開發工作。緊跟技術更新節奏,了解企業需求,不斷更新課程大綱。工作用什麼,就有什麼。高度專注,深度優化,注重培養學員編程思維能力,起步目標鎖定中高級工程師,起薪8000-12000!

⑼ 什麼是數控機床的混合編程

答:簡單的說就是絕對編程與增量編程一起編。 全面的如下: 數控機床編程時,可採用絕對值編程、增量值編程或二者混合編程。
1、絕對值編程
絕對值編程是根據預先設定的編程原點計算出絕對值坐標尺寸進行編程的一種方法。即採用絕對值編程時,首先要指出編程原點的位置,並用地址x、Z進行編程(X為直徑值)。有的數控系統用G90指令指定絕對值編程。
2、增量值編程
增量值編程是根據與前一個位置的坐標值增量來表示位置的一種編程方法。即程序中的終點坐標是相對於起點坐標而言的。採用增量值編程時,用地址U、W代替X、Z進行編程。
3、混合編程
絕對值編程與增量值編程混合起來進行編程的方法叫混合編程。編程時也必須先設定編程原點。

python與c++混合編程如何入門

派桑和c/c++實際上是不同的工具,一個是斧頭,一個是菜刀,各有各的用途。非要把讓菜刀能砍柴,讓斧頭能切菜,這種努力有無必要,值得考慮。
派桑常用劇本,嚕蘇,速度慢,不嚴謹,但有它的便利,例如它有 list, tuple, 之類的東西。
混合編程 常用於 提高 派桑 速度。
常用 方法 是(1)包含 Python.h 文件頭 (2)定義 派桑 的 各種對象 為 各種 c 結構
(3)派桑 的 各種對象用指針,名字用 Py 或 _Py大頭 動態分配 在 heap (4)用函數跟蹤統計 各種對象結構 的個數變化,即時 釋放內存(5)及時處理 派桑 exception
(6) 輸出為派桑的數據格式。
我沒有合起來用過,不過基本套路如此。

熱點內容
安卓手機如何有蘋果的emoji 發布:2025-02-09 02:11:02 瀏覽:807
編譯原理已知語言求文法習題 發布:2025-02-09 02:05:15 瀏覽:131
中國首個具有世界影響力的編譯器 發布:2025-02-09 01:56:21 瀏覽:719
tomcat上傳超時 發布:2025-02-09 01:41:42 瀏覽:483
androidactivity豎屏 發布:2025-02-09 01:41:40 瀏覽:377
家庭配置怎麼合理 發布:2025-02-09 01:36:14 瀏覽:807
頭條軍事源碼 發布:2025-02-09 01:31:53 瀏覽:997
androidintent視頻 發布:2025-02-09 01:31:43 瀏覽:858
歐姆龍plc密碼如何設置 發布:2025-02-09 01:24:31 瀏覽:687
php支持jpeg 發布:2025-02-09 01:24:22 瀏覽:803