diff --git a/README.md b/README.md index b6a0de5..958cc51 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ - [x] [volatile那些事](./volatile) - [x] [assert那些事](./assert) - [x] [位域那些事](./bit) +- [x] [extern那些事](./extern) ## 关于作者: 个人公众号: diff --git a/assert/README.md b/assert/README.md index b935168..534fc49 100644 --- a/assert/README.md +++ b/assert/README.md @@ -1,5 +1,13 @@ # assert那些事 +## 关于作者: + +个人公众号: + +![](../img/wechat.jpg) + + + ## 1.第一个断言案例 断言,**是宏,而非函数**。assert 宏的原型定义在 (C)、(C++)中,其作用是如果它的条件返回错误,则终止程序执行。可以通过定义 NDEBUG 来关闭 assert,但是需要在源代码的开头,include 之前。 diff --git a/bit/README.md b/bit/README.md index b9514fa..69fd9ff 100644 --- a/bit/README.md +++ b/bit/README.md @@ -1,8 +1,8 @@ +## 关于作者: +个人公众号: -[TOC] - - +![](../img/wechat.jpg) ## Bit field 是什么? diff --git a/extern/README.md b/extern/README.md new file mode 100644 index 0000000..40d973c --- /dev/null +++ b/extern/README.md @@ -0,0 +1,193 @@ +# extern "C" + +## 关于作者: + +个人公众号: + +![](../img/wechat.jpg) + +## 1.C++与C编译区别 + +在C++中常在头文件见到extern "C"修饰函数,那有什么作用呢? 是用于C++链接在C语言模块中定义的函数。 + +C++虽然兼容C,但C++文件中函数编译后生成的符号与C语言生成的不同。因为C++支持函数重载,C++函数编译后生成的符时带有函数参数类型的信息,而C则没有。 + +例如`int add(int a, int b)`函数经过C++编译器生成.o文件后,`add`会变成形如`add_int_int`之类的, 而C的话则会是形如`_add`, 就是说:相同的函数,在C和C++中,编译后生成的符号不同。 + +这就导致一个问题:如果C++中使用C语言实现的函数,在编译链接的时候,会出错,提示找不到对应的符号。此时`extern "C"`就起作用了:告诉链接器去寻找`_add`这类的C语言符号,而不是经过C++修饰的符号。 + +## 2.C++调用C函数 + +C++调用C函数的例子: 引用C的头文件时,需要加`extern "C"` + +```c++ +//add.h +#ifndef ADD_H +#define ADD_H +int add(int x,int y); +#endif + +//add.c +#include "add.h" + +int add(int x,int y) { + return x+y; +} + +//add.cpp +#include +#include "add.h" +using namespace std; +int main() { + add(2,3); + return 0; +} +``` + +编译: + +``` +//Generate add.o file +gcc -c add.c +``` + +链接: + +``` +g++ add.cpp add.o -o main +``` + +没有添加extern "C" 报错: + +```c++ +> g++ add.cpp add.o -o main +add.o:在函数‘main’中: +add.cpp:(.text+0x0): `main'被多次定义 +/tmp/ccH65yQF.o:add.cpp:(.text+0x0):第一次在此定义 +/tmp/ccH65yQF.o:在函数‘main’中: +add.cpp:(.text+0xf):对‘add(int, int)’未定义的引用 +add.o:在函数‘main’中: +add.cpp:(.text+0xf):对‘add(int, int)’未定义的引用 +collect2: error: ld returned 1 exit status +``` + +添加extern "C"后: + +`add.cpp` + +```c++ +#include +using namespace std; +extern "C" { + #include "add.h" +} +int main() { + add(2,3); + return 0; +} +``` + +编译的时候一定要注意,先通过gcc生成中间文件add.o。 + +``` +gcc -c add.c +``` + +然后编译: + +``` +g++ add.cpp add.o -o main +``` + +上述案例源代码见: + +- [add.h](extern_c++/add.h) + +- [add.c](extern_c++/add.c) + +- [add.cpp](extern_c++/add.cpp) + +## 2.C中调用C++函数 + +`extern "C"`在C中是语法错误,需要放在C++头文件中。 + +```c +// add.h +#ifndef ADD_H +#define ADD_H +extern "C" { + int add(int x,int y); +} +#endif + +// add.cpp +#include "add.h" + +int add(int x,int y) { + return x+y; +} + +// add.c +extern int add(int x,int y); +int main() { + add(2,3); + return 0; +} +``` + +编译: + +```c +g++ -c add.cpp +``` + +链接: + +``` +gcc add.c add.o -o main +``` + +上述案例源代码见: + +- [add.h](extern_c/add.h) + +- [add.c](extern_c/add.c) + +- [add.cpp](extern_c/add.cpp) + +综上,总结出使用方法,在C语言的头文件中,对其外部函数只能指定为extern类型,C语言中不支持extern "C"声明,在.c文件中包含了extern "C"时会出现编译语法错误。所以使用extern "C"全部都放在于cpp程序相关文件或其头文件中。 + +总结出如下形式: + +(1)C++调用C函数: + +```c++ +//xx.h +extern int add(...) + +//xx.c +int add(){ + +} + +//xx.cpp +extern "C" { + #include "xx.h" +} +``` + +(2)C调用C++函数 + +```c +//xx.h +extern "C"{ + int add(); +} +//xx.cpp +int add(){ + +} +//xx.c +extern int add(); +``` + diff --git a/extern/extern_c++/add.c b/extern/extern_c++/add.c new file mode 100644 index 0000000..b347468 --- /dev/null +++ b/extern/extern_c++/add.c @@ -0,0 +1,5 @@ +#include "add.h" + +int add(int x,int y) { + return x+y; +} diff --git a/extern/extern_c++/add.cpp b/extern/extern_c++/add.cpp new file mode 100644 index 0000000..8ed76fa --- /dev/null +++ b/extern/extern_c++/add.cpp @@ -0,0 +1,9 @@ +#include +using namespace std; +extern "C" { + #include "add.h" +} +int main() { + add(2,3); + return 0; +} diff --git a/extern/extern_c++/add.h b/extern/extern_c++/add.h new file mode 100644 index 0000000..6984cdf --- /dev/null +++ b/extern/extern_c++/add.h @@ -0,0 +1,4 @@ +#ifndef ADD_H +#define ADD_H +extern int add(int x,int y); +#endif diff --git a/extern/extern_c++/add.o b/extern/extern_c++/add.o new file mode 100644 index 0000000..4c8c016 Binary files /dev/null and b/extern/extern_c++/add.o differ diff --git a/extern/extern_c++/main b/extern/extern_c++/main new file mode 100755 index 0000000..451dd01 Binary files /dev/null and b/extern/extern_c++/main differ diff --git a/extern/extern_c/add.c b/extern/extern_c/add.c new file mode 100644 index 0000000..6f8a3d8 --- /dev/null +++ b/extern/extern_c/add.c @@ -0,0 +1,5 @@ +extern int add(int x,int y); +int main() { + add(2,3); + return 0; +} diff --git a/extern/extern_c/add.cpp b/extern/extern_c/add.cpp new file mode 100644 index 0000000..b347468 --- /dev/null +++ b/extern/extern_c/add.cpp @@ -0,0 +1,5 @@ +#include "add.h" + +int add(int x,int y) { + return x+y; +} diff --git a/extern/extern_c/add.h b/extern/extern_c/add.h new file mode 100644 index 0000000..719b7c3 --- /dev/null +++ b/extern/extern_c/add.h @@ -0,0 +1,6 @@ +#ifndef ADD_H +#define ADD_H +extern "C" { + int add(int x,int y); +} +#endif diff --git a/extern/extern_c/add.o b/extern/extern_c/add.o new file mode 100644 index 0000000..564710e Binary files /dev/null and b/extern/extern_c/add.o differ diff --git a/extern/extern_c/main b/extern/extern_c/main new file mode 100755 index 0000000..f026f11 Binary files /dev/null and b/extern/extern_c/main differ diff --git a/volatile/README.md b/volatile/README.md index f4dbcde..1090d42 100644 --- a/volatile/README.md +++ b/volatile/README.md @@ -1,4 +1,11 @@ +## 关于作者: + +个人公众号: + +![](../img/wechat.jpg) + ## 1.volatile + 被 `volatile` 修饰的变量,在对其进行读写操作时,会引发一些**可观测的副作用**。而这些可观测的副作用,是由**程序之外的因素决定的**。 ## 2.volatile应用