混合调用,单链表的基本操作官方澳门新永利下载:

按C语言代码编写

在品种中,C和C++代码相互调用是很常见的,但在调用时,究竟应该怎么着编写代码和头文件,有局地爱戴,不然就或然出现编写翻译时链接不通过的难题,标准的编写翻译错误日志是:

  • 节点
undefined reference to `xxx'

要编写出C或C++都能寻常调用的代码,必要知道编写翻译器在编写翻译时,毕竟做了什么样。上面就以几段轻松的代码为例,来验证一下GCC种类编写翻译器在编写翻译C、C++代码时,分别做了怎么,大家该怎么编写自身的函数库以供C和C++代码调用。

typedef struct Student { char name[20]; //学生姓名 int num; //学号 struct Student *next;}node; //node为struct Student的别名

本文表明的情状是:Ubuntu Server 18.04 LTS,gcc/g++ 7.3.0,nm 2.30

  • 链表的创办

C函数库怎样被C和C++代码调用

sum.c是贰个用到C代码编写的对整数求和函数,代码特别轻易:

1 #include "sum.h"2 3 int sum(int a, int b)4 {5     return a + b;6 }

在不想念C++的调用时,头文件sum.h常常会奉公守法如下写法:

1 #ifndef __SUM_H__2 #define __SUM_H__3 4 int sum(int a, int b);5 6 #endif /* __SUM_H__ */

小编们编辑上边包车型客车main.cpp代码来调用它:

 1 #include <iostream> 2  3 #include "sum.h" 4  5 int main(void) 6 { 7     std::cout << sum(1, 1) << std::endl; 8      9     return 0;10 }

编写翻译并运维一向下探底访:

$ g++ -o main main.cpp sum.c$ ./main 2

从结果来看,未有其它难点,程序平常编写翻译通过和推行。

不过,要是sum.c是要做成叁个库文件,可供C或C++代码调用时,又该怎么样呢?以静态库为例,sum.c是先编译成.o文件,再和任何的同类文件一同装进到.a中,由于独有八个文件,这里就不把它包裹到.a文件了,仅把它生成八个.o文件作为函数库看一下:

$ gcc -c sum.c$ g++ -o main main.cpp sum.o/tmp/ccNnKecX.o: In function `main':main.cpp:(.text+0xf): undefined reference to `sum(int, int)'collect2: error: ld returned 1 exit status

从上述输出能够看出,链接是无法透过的。编写翻译器告诉我们,那一个引用未有概念。但大家都清楚,sum函数是开诚布公存在的。出现这种难题的缘由,在于C++是援救面向对象的,函数能够重载,为了支持重载,编写翻译时生成的.o文件中,函数名称不会像源文件那样。用nm列出指标文件中的符号,就足以看出实际的场地:

$ nm sum.o0000000000000000 T sum$ g++ -c main.cpp$ nm main.o                  U __cxa_atexit                 U __dso_handle                 U _GLOBAL_OFFSET_TABLE_0000000000000086 t _GLOBAL__sub_I_main0000000000000000 T main                 U _Z3sumii000000000000003d t _Z41__static_initialization_and_destruction_0ii                 U _ZNSolsEi                 U _ZNSolsEPFRSoS_E                 U _ZNSt8ios_base4InitC1Ev                 U _ZNSt8ios_base4InitD1Ev                 U _ZSt4cout                 U _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_0000000000000000 r _ZStL19piecewise_construct0000000000000000 b _ZStL8__ioinit

从下面的输出中,大家得以看见,用gcc命令编写翻译生成的sum.o,包括有二个标识sum。可是用g++编写翻译出来的main.o,它里面援用到sum函数时,用的名字其实是_Z3sumii,那几个便是g++编写翻译器对C++代码做的管理。由于sum.o中并从未_Z3sumii函数,链接当然要倒闭。

那么,为何一开头的下令g++ -o main main.cpp
sum.c能健康生成可执行文件呢,因为在那条命令试行时,对sum.c也作为是C++代码来拍卖的,大家得以对sum.c调用g++命令来讲喜宝(Hipp)下:

$ g++ -c sum.c$ nm sum.o0000000000000000 T _Z3sumii

可知,对于C源文件,调用g++命令时,是把C代码视作C++来拍卖的。对于C++文件去调用gcc命令,又当什么呢?风乐趣的能够活动尝试一下,这里就不再举办了,仅付给两个准绳:

  • 对此C代码,使用gcc命令去编写翻译,让编写翻译器按C代码的条条框框来拍卖,那样有利于另外C代码调用,如若遵照C++代码管理了,即使C++调用是造福了,但别的C代码调用就劳动了
  • 对此C++代码,使用g++命令编写翻译,按C++的条条框框处理

略知一二了编写翻译器会做什么样后,大家看一下怎样让C++调用C函数库。查看系统库的标准头文件,我们会看精粹多这么的代码:

1 #ifdef __cplusplus2 extern "C" {3 #endif4 ...5 #ifdef __cplusplus6 }7 #endif

骨子里,extern “C”正是告诉编写翻译器,使用extern
“C”修饰的代码是用C的指标文件格式来编写翻译的,那样符号名称即便坚守C的指令准绳去寻找和扭转。extern
“C”有三种样式,一种是修饰单行语句的,比如:

extern "C" int sum(int a, int b);

这种样式能够独立写在有个别源代码文件中,但不分布。另一种是对整块代码做修饰,比方:

extern "C" {    int sum(int a, int b);    ...}

为何系统头文件要加#ifdef __cplusplus呢,因为C编写翻译器不认知extern
“C”,假设插入这些,C编写翻译器就要报错,所以,只应该对C++代码这么定义,由于在编写翻译C++代码时,编写翻译器会自动定义宏__cplusplus,由此,就足以运用那几个宏来做标准编写翻译。现在,大家把sum.h改形成:

 1 #ifndef __SUM_H__ 2 #define __SUM_H__ 3  4 #ifdef __cplusplus 5 extern "C" { 6 #endif 7  8     int sum(int a, int b); 9 10 #ifdef __cplusplus11 }12 #endif13 14 #endif /* __SUM_H__ */

接下来,重新行使原本报错的授命试试:

$ gcc -c sum.c$ g++ -o main main.cpp sum.o$ ./main 2

那般就成功了。总计下来,正是C头文件中,加上extern “C”
{}那样的扬言,并对C代码仍是按C语言的章程编写翻译,那样做,C或C++代码调用都不曾难题。
extern
“C”还会有另一个用法,有个别已经存在的C函数库及其头文件,并未有做那样的拍卖,那C++代码又当什么引用呢?答案是在C++代码中,依据如下格局编写代码:

extern {#include "C_header.h"}

C代码如何调用C++的函数

这里,依旧选取同一的亲自过问来证实,只是反过来,sum.cpp如下:

#include "sum.h"int sum(int a, int b){    return a + b;}

sum.h如下:

#ifndef __SUM_H__#define __SUM_H__#ifdef __cplusplusextern "C" {#endif    int sum(int a, int b);#ifdef __cplusplus}#endif#endif /* __SUM_H__ */

main.c如下:

 1 #include <stdio.h> 2  3 #include "sum.h" 4  5 int main(void) 6 { 7     printf("%dn", sum(1, 1)); 8  9     return 0;10 }

编写翻译运行结果如下:

$ g++ -c sum.cpp$ nm sum.o0000000000000000 T sum$ gcc -o main main.c sum.o$ ./main2

从此处还是可以够看来,extern “C”在起效能,要是把extern
“C”的一部分去掉,再编写翻译时,就能够见到链接可是的唤醒:

$ g++ -c sum.cpp$ nm sum.o0000000000000000 T _Z3sumii$ gcc -o main main.c sum.o/tmp/ccJkz0dn.o: In function `main':main.c:(.text+0xf): undefined reference to `sum'collect2: error: ld returned 1 exit status

竭泽而渔此难点的最简便易行方法,就是对main.c调用g++命令,由于C++对C的宽容性,那样做完全寻常:

$ g++ -o main main.c sum.o$ ./main2

自然,那只适用于非成员函数,假设想在C代码中调用成员函数,由于涉及到类,须要非凡的包裹,这里,我们把这些函数放在贰个类Math里,作为三个静态成员函数来演示,非静态成员函数的景况更麻烦,建议直接使用C++代码来拍卖后,再封装成静态成员的点子做转变,示例的math.h:

 1 class Math { 2 public: 3     static int sum(int a, int b); 4 };

示例的math.cpp:

1 #include "math.h"2 3 int Math::sum(int a, int b)4 {5     return a + b;6 }

编辑的卷入器头文件math_wrapper.h:

 1 #ifndef __MATH_WRAPPER_H__ 2 #define __MATH_WRAPPER_H__ 3  4 #ifdef __cplusplus 5 extern "C" { 6 #endif 7  8     int sum(int a, int b); 9 10 #ifdef __cplusplus11 }12 #endif13 14 #endif /* __MATH_WRAPPER_H__ */

包装器代码math_wrapper.cpp:

1 #include "math.h"2 #include "math_wrapper.h"3 4 int sum(int a, int b)5 {6     return Math::sum;7 }

编写翻译上述代码并查阅符号:

$ g++ -c math.cpp$ nm math.o$ g++ -c math_wrapper.cpp$ nm math_wrapper.o                 U _GLOBAL_OFFSET_TABLE_0000000000000000 T sum                 U _ZN4Math3sumEii

我们能够看看,math_wrapper.o把符号成功地转移了,写个main.c调用一下:

#include <stdio.h>#include "math_wrapper.h"int main(void){    printf("%dn", sum(1, 1));    return 0;}

编写翻译运维毫无难题:

$ gcc -o main main.c math_wrapper.o math.o$ ./main2

基本思路正是:对已经依照C++的法子调换的C++库,用C++写个包装器来援用它的函数,但命名法则使用C的办法管理,那样就把函数调换来C代码能够调用的了,假若函数重载了,就写八个函数来退换。

node *creat() { node *head = NULL, *tail = NULL; node *pNode = malloc(sizeof; scanf("%s%d", pNode->name, &pNode->num); while(pNode->num) { //这里以学号为零结束创建 if head = tail = pNode; tail->next = pNode; tail = pNode; pNode = malloc(sizeof; scanf("%s%d", pNode->name, &pNode->num); } if tail->next = NULL;//注意,条件不可以省 return head;}
  • 输出

void output(node *head) { if printf("This list is empty!n"); node *pNode; for(pNode = head; pNode; pNode = pNode->next) printf("%st%dn", pNode->name, pNode->num);}
  • 查找

//通过姓名查找某位同学的具体信息node *find(node *head, const char *name) { node *pNode = NULL; for(pNode = head; pNode; pNode = pNode->next) if(!strcmp(pNode->name, name)) return pNode; return pNode;}
  • 修改

发表评论

电子邮件地址不会被公开。 必填项已用*标注