当前位置:首页 » 编程软件 » c混合编程

c混合编程

发布时间: 2023-06-26 13:48:08

❶ matlab与c混合编程,engOpen()的问题,matlab引擎启动不了

使用engOpen()打开Matlab引擎总是失败,问题可能就是Matlab组件没有注册。注册方法:点击开始/运行/cmd,在命令行提示窗口下更改到Matlab安装路径/bin,运行指令
matlab/regserver,注册成功后会弹出Matlab 命令窗口。

❷ 汇编语言和c语言混合编程时,它们之间是如何传递参数的请用具体例子说明

变量本质就是一个内存地址,所以把变量负值到寄存器就可以了,比如这样__asm mov eax, var,如果是函数,跟c函数一样调用,当然,也可以用汇编写一个动态链接库,然后用c调用,你可以把c程序逆向一下,就可以看到它们的对应关系了,呵

❸ 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的好处。

❹ matlab和c混合编程如何运行

简单点的,你就用matlab写一个接口程序,封装你的c程序,类似下面这种:(matlab的例子,实现数组相乘,文件为arrayProct.c)

#include "mex.h"

/* 你的c */
void arrayProct(double x, double *y, double *z, mwSize n)
{
mwSize i;
/* multiply each element y by x */
for (i=0; i<n; i++) {
z[i] = x * y[i];
}
}

/* 接口程序 */
void mexFunction( int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[])
{
/*初始化输入输出*/
double multiplier; /* input scalar */
double *inMatrix; /* 1xN input matrix */
mwSize ncols; /* size of matrix */
double *outMatrix; /* output matrix */

/* 参数检查,如果程序较简单也可以不用做*/
if(nrhs!=2) {
mexErrMsgIdAndTxt("MyToolbox:arrayProct:nrhs","Two inputs required.");
}
if(nlhs!=1) {
mexErrMsgIdAndTxt("MyToolbox:arrayProct:nlhs","One output required.");
}
/* make sure the first input argument is scalar */
if( !mxIsDouble(prhs[0]) ||
mxIsComplex(prhs[0]) ||
mxGetNumberOfElements(prhs[0])!=1 ) {
mexErrMsgIdAndTxt("MyToolbox:arrayProct:notScalar","Input multiplier must be a scalar.");
}

/* check that number of rows in second input argument is 1 */
if(mxGetM(prhs[1])!=1) {
mexErrMsgIdAndTxt("MyToolbox:arrayProct:notRowVector","Input must be a row vector.");
}

/* get the value of the scalar input */
multiplier = mxGetScalar(prhs[0]);

/* create a pointer to the real data in the input matrix */
inMatrix = mxGetPr(prhs[1]);

/* get dimensions of the input matrix */
ncols = mxGetN(prhs[1]);

/* create the output matrix */
plhs[0] = mxCreateDoubleMatrix(1,ncols,mxREAL);

/* get a pointer to the real data in the output matrix */
outMatrix = mxGetPr(plhs[0]);

/* call the computational routine */
arrayProct(multiplier,inMatrix,outMatrix,ncols);
}

这个看起来复杂,其实很简单的,就几步:
1、使用mxGet*将输入变为matlab兼容形式
2、使用mxSet*初始化输出空间
3、使用你的C程序运算

❺ 怎么实现c语言与汇编语言的混合编程

这个问题有很多做法。如果你的汇编语句比较简单可以采用楼上的做法。
如果的你的汇编比较大,可以写成另外一个汇编文件*.asm。然后根据你的编译器给你的指令,把你的汇编函数抽象出C语言声明。做成*.h文件,供其他人调用。这是现在比较流行的底层API开发模式。
如 我把需要用汇编语句写的功能写一个汇编文件 asm_main.asm,我在该文件的前面 加一句 XDEF asm_main(这是我的编译器的规定,用XDEF),然后在asm_main.h里声明(就是典型的C声明 如 U16 asm_main())。这样你在你的C程序中如果用到汇编功能,只要#include "asm_main.h" 就可以调用用汇编写的函数了。对于大规模的软件开发,这是个很重要的方法。它提供了二次接口供上层调用。你可以把所有硬件驱动或底层API都写成这样子。C语言开发者就不需要了解底层硬件细节了。而且底层汇编的改动也不会影响C。这样你开发的C程序可移植性就高了。当然,你还需要些编译原理的知识。如,在汇编里,asm_main函数只是个标号,写成asm_main: 对吧,但是如果你需要些入口参数怎么办?比如你要抽象出U16 asm_main(char ,char *),这个时候你要考虑参数是怎样入栈的,一般是从右到左依次压栈的,等等还有些问题。
现在的大学本科教育只教一些单片机开发的小技能,没有一个系统的概念。我很愿意把我工作中得来的经验与大家分享。

❻ 为什么要C和汇编混合编程

依我的看法,上面两位说的都不对:
一楼:汇编语言是低级语言直接往硬件的寄存器里写入东西:
其实C语言和汇编语言都一样,都会编译成二进制文件机器语言烧录到单片机中,所以没有一楼所说的区别

二楼:在C中也不会有数据损失的,如果你定义好数据类型的话。

单片机中是将C编译成汇编,然后根据汇编编译成机器语言---可执行文件;
其实单片机中经常在C中嵌入汇编,主要是因为时间的关系,因为一条汇编语言执行的时间都是可以知道的,而C指令执行的时间是不可知的,因为C编译器不一样,编译后的汇编也是不一样的,如果用汇编就不会有这种情况。所以在一些精确延时的场合,要嵌入汇编
另外,C的可移植性较强,不同的单片机里,功能要求相同的可以直接拿去用
总之,汇编是程序员可以自己翻译成机器语言的,所以单片机的运行是可以完全掌握的

❼ 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 ); 试一试。

❽ C/C++与汇编混合编程有什么好处

当需要C/C++与汇编混合编程时,可以有以下两种处理策略:

  • 若汇编代码较短,则可在C/C++源文件中直接内嵌汇编语言实现混合编程。

  • 若汇编代码较长,可以单独写成汇编文件,最后以汇编文件的形式加入项目中,通过ATPCS规定与C程序相互调用及访问

  • 后缀.S文件中的汇编指令是用armasm汇编器进行汇编的,而C语言程序中的内嵌汇编指令则是用内嵌汇编器进行汇编的。这两种汇编器存在一定的差异,所以在内嵌汇编时要注意以下几点。

  • 2.3.1 小心使用物理寄存器

  • 必须小心使用物理寄存器,如R0~R3、IP(R12)、LR(R14)和CPSR中的N、Z、C、V标志位。因为计算汇编代码中的C表达式时,可能使用这些物理寄存器,并会修改N、Z、C、V标志位。

  • 如计算:

  • y=x+x/y;

  • [cpp] view plain

  • 1. __asm

  • 2. {

  • 3. MOV R0, x //把x的值给R0

  • 4. ADD y, R0, x/y //计算x/y时R0的值会被修改

  • 5. }

  • 2.3.2 内嵌汇编程序中允许使用C变量

  • 在计算x/y时R0会被修改,从而影响R0+x/y的结果。内嵌汇编程序中允许使用C变量,用C变量来代替寄存器R0可以解决上述问题。这时内嵌汇编器将会为变量var分配合适的存储单元,从而避免冲突的发生。如果内嵌汇编器不能分配合适的存储单元,它将会报告错误。

  • [cpp] view plain

  • 1. int var;

  • 2. __asm

  • 3. {

  • 4. MOV var, x //把x的值给R0

  • 5. ADD y, var, x/y //计算x/y时R0的值会被修改

  • 6. }

  • 2.3.3 不需要保存和恢复用到的寄存器

  • 对于在内嵌汇编语言程序中用到的寄存器,编译器在编译时会自动保存和恢复这些寄存器,用户不用保存和恢复这些寄存器。除了CPSR和SPSR寄存器外,其他物理寄存器在读之前必须先赋值,否则编译器会报错。

  • [cpp] view plain

  • 1. int fun (int x)

  • 2. {

  • 3. __asm

  • 4. {

  • 5. STMFD SP!, {R0} //保存R0,先读后写,汇编出错

  • 6. ADD R0, x, #1

  • 7. EOR x, R0, x

  • 8. LDMFD SP!, {R0} //多余的

  • 9. }

  • 10. return x;

  • 11. }

❾ 如何实现C与python混合编程

实现C与python混合编程方法
代码如下:

/* tcpportping.c */
#include <Python.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/time.h>

/* count time functions */
static double mytime(void)
{
struct timeval tv;
if (gettimeofday(&tv, NULL) == -1)
return 0.0;

return (double)tv.tv_usec + (double)tv.tv_sec * 1000000;
}

static PyObject * /* returns object */
tcpping(PyObject *self, PyObject *args )
{
struct sockaddr_in addr;
struct hostent *hp;
double time;
char *host = NULL;
int fd;
int port, timeout;

if (!PyArg_ParseTuple(args, "sii", &host, &port, &timeout)) /* convert Python -> C */
return NULL; /* null=raise exception */

if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
return Py_BuildValue("d", -1.0); /* convert C -> Python */
}

bzero((char *)&addr, sizeof(addr));
if ((hp = gethostbyname(host)) == NULL) {
return Py_BuildValue("d", -2.0); /* convert C -> Python */
}
b(hp->h_addr, &addr.sin_addr, hp->h_length);
addr.sin_family = AF_INET;
addr.sin_port = htons(port);

struct timeval tv;

tv.tv_sec = 0;
tv.tv_usec = timeout * 1000;

double stime = mytime();
if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
return Py_BuildValue("d", -3.0); /* convert C -> Python */
}
fd_set read, write;
FD_ZERO(&read);
FD_ZERO(&write);

FD_SET(fd, &read);
FD_SET(fd, &write);

if (select(fd + 1, &read, &write, NULL, &tv) == 0) {
close(fd);
return Py_BuildValue("d", -4.0); /* convert C -> Python */
}

double etime = mytime();
time = etime - stime;
if (!FD_ISSET(fd, &read) && !FD_ISSET(fd, &write)) {
close(fd);
return Py_BuildValue("d", -4.0); /* convert C -> Python */
}
close(fd);
return Py_BuildValue("d", time/1000); /* convert C -> Python */
}

/* registration table */
static struct PyMethodDef portping_methods[] = {
{"tcpping", tcpping, METH_VARARGS}, /* method name, C func ptr, always-tuple */
{NULL, NULL} /* end of table marker */
};

/* mole initializer */
void inittcpportping( ) /* called on first import */
{ /* name matters if loaded dynamically */
(void) Py_InitMole("tcpportping", portping_methods); /* mod name, table ptr */
}

热点内容
双向的访问了你的空间 发布:2025-02-08 13:13:20 浏览:699
python元素是否在list 发布:2025-02-08 13:11:38 浏览:694
安卓现在哪个最好用 发布:2025-02-08 13:06:27 浏览:791
百度网盘上传错误 发布:2025-02-08 12:56:21 浏览:69
安卓手机怎么解除防抖系统 发布:2025-02-08 12:55:37 浏览:391
sql2008sql代理 发布:2025-02-08 12:55:34 浏览:52
vs编译找不到指定项目文件 发布:2025-02-08 12:36:54 浏览:243
怎样用windows服务器搭建网站 发布:2025-02-08 12:27:38 浏览:532
android获取音乐 发布:2025-02-08 12:26:05 浏览:962
存储的数据可以复制吗 发布:2025-02-08 12:20:22 浏览:852