extern C 在c/c++中的使用

2023-11-17

http://blog.csdn.net/jscese/article/details/37821961

1 : 问题定义

在研究操作系统源代码或者在嵌入式系统中编写程序时,经常会发现下面这种用法:

[cpp]  view plain  copy  print ?
  1. #ifndef __OTHER_FILE_C_H__--------------------防止一个文件中多次包含这个头文件  
  2.   
  3. #define __OTHER_FILE_C_H__--------------------防止一个文件中多次包含这个头文件  
  4.   
  5. #ifdef __cplusplus------------------------如果使用的是C++编译器  
  6. extern "C" {  
  7. #endif  
  8.   
  9.    
  10.   
  11. ……  
  12.   
  13. extern void c_main();-----这部分内容一般是函数声明或一些数据结构的定义等  
  14.   
  15. ……  
  16.   
  17.   
  18. #ifdef __cplusplus------------------------如果使用的是C++编译器  
  19. }  
  20. #endif  
  21.   
  22. #endif  


 

其实extern “C”可以用在函数定义之前,也可以用在函数声明之前。这两者的区别在后续内容中将会讲到,但是一般用在函数声明之前。

或许大家都知道,extern “C”的作用就是在C++环境中使函数按照C的标准来编译和链接,但这种说话不全面。比如说当extern “C”放在函数声明之前,就不会改变函数的编译方式,只是指定编译器按照C的标准链接,而不是按照C++的标准去链接函数。

其实在头文件.h中下面这种用法

extern “C” externvoid c_main();

等效与在 .cpp文件中直接用extern “C” void c_main();

但是有四个问题值得我们仔细思考:

1、        在C++编译环境(VC 6.0)中,工程文件中同时包含.c文件和.cpp文件,那么编译.c和.cpp按照什么编译规则来编译的,有什么区别?

2、        在C++编译环境中, extern “C”放在函数声明之前的作用是什么?

3、        加了cpp文件中在函数声明前加extern “C”的作用是什么?

4、        那么什么情况下才需要使用extern “C”呢?

除非有特别指出特定的编译器,否则以下采用的实验环境默认是VC 6.0。


2 :原理

C++语言的创建初衷是“a better C”,但是这并不意味着C++中类似C语言的全局变量和函数所采用的编译和连接方式与c语言完全相同。作为一种欲与C兼容的语言,C++保留了一部分过程式语言的特点(被世人称为“不彻底地面向对象”),因而它可以定义不属于任何类的全局变量和函数。但是,C++毕竟是一种面向对象的程序设计语言,为了支持函数的重载,C++对全局函数的处理方式与C有明显的不同。

 

extern "C" 包含双重含义,从字面上即可得到:首先,被它修饰的目标是“extern”的;其次,被它修饰的目标是“C”的。让我们来详细解读这两重含义。

1.    被extern"C"限定的函数或变量是extern类型的;

2.    extern是C/C++语言中表明函数和全局变量作用范围(可见性)的关键字,该关键字告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。记住,下列语句:extern int a;仅仅是一个变量的声明,其并不是在定义变量a,并未为a分配内存空间。变量a在所有模块中作为一种全局变量只能被定义一次,否则会出现连接错误。

通常,在模块的头文件中对本模块提供给其它模块引用的函数和全局变量以关键字extern声明。例如,如果模块B欲引用该模块A中定义的全局变量和函数时只需包含模块A的头文件即可。这样,模块B中调用模块A中的函数时,在编译阶段,模块B虽然找不到该函数,但是并不会报错;它会在连接阶段中从模块A编译生成的目标代码中找到此函数。

与extern对应的关键字是static,被它修饰的全局变量和函数只能在本模块中使用。因此,一个函数或变量只可能被本模块使用时,其不可能被extern “C”修饰。

被extern "C"修饰的变量和函数是按照C语言方式编译和连接的;

未加extern “C”声明时的编译方式:

首先看看C++中对类似C的函数是怎样编译的。

作为一种面向对象的语言,C++支持函数重载,而过程式语言C则不支持。函数被C++编译后在符号库中的名字与C语言的不同。例如,假设某个函数的原型为:

void c_main();

该函数被C编译器编译后在符号库中的名字为_ c_main,而C++编译器则会产生像

?c_main2@@YAXXZ之类的名字(不同的编译器可能生成的名字不同,但是都采用了相同的机制)。

3:分析

3.1:VC中.c与.cpp的编译规则

问题:在C++编译环境(VC 6.0)中,工程文件中同时包含.c文件和.cpp文件,那么编译.c和.cpp按照什么编译规则来编译的,有什么区别?

解答:在VC 6.0工程文件中,可能含有.cpp文件和.c文件混合编译。在.c的源文件按照C的标准来编译,函数名之前加入”_”,并把“_函数名”放入到符号表中,以后链接时使用。.cpp的源文件按照C++的标准编译,会修改函数名,这个不同的编译器有不同的实现方式,在VC中,函数名被修改的有些乱,如下:

 testC.c文件中的代码:

[cpp]  view plain  copy  print ?
  1. #include "stdio.h"  
  2.   
  3. void c_main()  
  4.   
  5. {  
  6.   
  7.       printf ("this isc program\n!");  
  8.   
  9. }  


通过objdump工具反编译testC.obj文件为汇编代码为:

[html]  view plain  copy  print ?
  1. 00000000 <_c_main>:  
  2.   
  3.    0:   55                      push   %ebp  
  4.   
  5.    1:   8b ec                   mov    %esp,%ebp  
  6.   
  7.    3:   83 ec 40                sub    $0x40,%esp  
  8.   
  9.    6:   53                      push   %ebx  
  10.   
  11.    7:   56                      push   %esi  
  12.   
  13.    8:   57                      push   %edi  
  14.   
  15.    9:   8d 7d c0                lea    -0x40(%ebp),%edi  
  16.   
  17.    c:   b9 10 00 00 00          mov   $0x10,%ecx  
  18.   
  19.   11:   b8 cc cc cc cc          mov   $0xcccccccc,%eax  
  20.   
  21.   16:   f3 ab                   rep stos %eax,%es:(%edi)  
  22.   
  23.   18:   68 00 00 00 00          push   $0x0  
  24.   
  25.   1d:   e8 00 00 00 00          call  22 <_c_main+0x22>  
  26.   
  27.   22:   83 c4 04                add    $0x4,%esp  


有上述汇编代码可见,c_main函数编译后,函数名为_c_main(), 可见.c文件在VC中采用的是标准C的编译方式。

 testCPP.cpp文件中的代码

[html]  view plain  copy  print ?
  1. 00000000 <?c_main2@@YAXHHH@Z>:  
  2.   
  3.   0:   55                      push   %ebp  
  4.   
  5.   1:   8b ec                   mov    %esp,%ebp  
  6.   
  7.   3:   83 ec 40                sub    $0x40,%esp  
  8.   
  9.   6:   53                      push   %ebx  
  10.   
  11.   7:   56                      push   %esi  
  12.   
  13.   8:   57                      push   %edi  
  14.   
  15.   9:   8d 7d c0                lea    -0x40(%ebp),%edi  
  16.   
  17.   c:   b9 10 00 00 00          mov   $0x10,%ecx  
  18.   
  19.  11:   b8 cc cc cc cc          mov   $0xcccccccc,%eax  
  20.   
  21.  16:   f3 ab                   rep stos %eax,%es:(%edi)  
  22.   
  23.  18:   68 00 00 00 00          push  $0x0  
  24.   
  25.  1d:   e8 00 00 00 00          call  22 <?c_main2@@YAXHHH@Z+0x22>  
  26.   
  27.  22:   83 c4 04                add    $0x4,%esp  


上述汇编代码可见,c_main函数编译后,函数名为?c_main2@@YAXHHH@Z, 可见.cpp文件在VC中采用的是标准C++的编译方式。

 

3.2:extern “C”放在函数声明前的作用

问题:在C++编译环境中,用了(extern “C”+函数声明)与(不用extern “C”+函数声明),区别在哪?

解答:用(extern “C”+函数声明),表明CPP此文件中的函数,以C的标准来链接(“_函数名”), 如果在CPP文件中函数声明前不用extern “C”,则采用C++的标准来链接(比如函数名为”?c_main2@@YAXHHH@Z”)。

Ø  如果在test_a.cpp文件,有extern “C”放在函数声明之前,而其函数实现放在另外一个文件test_b.cpp中,则C++编译器不会改变test_b.cpp文件中函数的编译规则(还是按照c++的规则来编译),只是通知编译器在链接test_a.cpp中函数时采取C的标准方式链接函数。如:vc 6.0工程中有两个文件,一个为test_a.cpp, 另一个文件为test_b.cpp。 test_a.cpp文件中代码如下:

[cpp]  view plain  copy  print ?
  1. #include "stdio.h"  
  2.   
  3. extern "C" void c_main2(int a, int b, int c);  
  4.   
  5.    
  6.   
  7. void main(void)  
  8.   
  9. {  
  10.   
  11.      c_main2(0,0,0);  
  12.   
  13.      return ;  
  14.   
  15. }  
  16.   
  17. test_b.cpp文件中的代码如下:  
  18.   
  19. #include <stdio.h>  
  20.   
  21.    
  22.   
  23. void c_main2(int a, int b, int c)  
  24.   
  25. {  
  26.   
  27.      printf ("this iscpp program\n!");  
  28.   
  29. }  


结果:编译通过,链接失败。

1、        通过objdump工具查看test_a.obj文件的符号表,发现链接时需要查找_c_main2()。

如下:

[html]  view plain  copy  print ?
  1. [ 14](sec  3)(fl0x00)(ty  20)(scl   2) (nx 1) 0x00000000 _main  
  2.   
  3. AUX tagndx 18 ttlsiz 0x37 lnnos 1224 next 0  
  4.   
  5. _main :  
  6.   
  7.    1 : 00000018  
  8.   
  9.    3 : 00000026  
  10.   
  11. [ 16](sec  0)(fl0x00)(ty  20)(scl   2) (nx 0) 0x00000000 _c_main2  
  12.   
  13. [ 17](sec  0)(fl0x00)(ty  20)(scl   2) (nx 0) 0x00000000 __chkesp  
  14.   
  15. [ 18](sec  3)(fl 0x00)(ty   0)(scl 101) (nx 1) 0x00000000 .bf  
  16.   
  17.    
  18.   
  19. 2、通过objdump工具反汇编test_b.obj,发现在c_main2()函数反汇编出来后,采用的是C++的编译方式进行的,函数名做了更改?c_main2@@YAXHHH@Z,如下:  
  20.   
  21. 00000000 <?c_main2@@YAXHHH@Z>:  
  22.   
  23.    0:   55                      push   %ebp  
  24.   
  25.    1:   8b ec                   mov    %esp,%ebp  
  26.   
  27.    3:   83 ec 40                sub    $0x40,%esp  
  28.   
  29.    6:   53                      push   %ebx  
  30.   
  31.    7:   56                      push   %esi  
  32.   
  33.    8:   57                      push   %edi  
  34.   
  35.    9:   8d 7d c0                lea    -0x40(%ebp),%edi  
  36.   
  37.    c:   b9 10 00 00 00          mov   $0x10,%ecx  
  38.   
  39.   11:   b8 cc cc cc cc          mov   $0xcccccccc,%eax  
  40.   
  41.   16:   f3 ab                   rep stos %eax,%es:(%edi)  
  42.   
  43.   18:   68 00 00 00 00          push  $0x0  
  44.   
  45.   1d:   e8 00 00 00 00          call  22 <?c_main2@@YAXHHH@Z+0x22>  
  46.   
  47.   22:   83 c4 04                add    $0x4,%esp  
  48.   
  49. 由于链接时在其他模块中找不到_c_main2()函数,故提示链接失败。  


 

3.3:extern “C”放在函数定义前的作用

问题:在cpp文件中在函数定义前加了extern “C”后,此的函数定义的编译方式是否会改变(按照c的编译方式编译还是按照c++的编译方式编译)?

Ø  解答: 会改变,如果extern “C”放在函数定义之前,则C++编译器使得函数按照C的标准来编译和链接函数。

如VC6.0工程中有以文件test.cpp,文件中代码内容如下:

[cpp]  view plain  copy  print ?
  1. #include"stdio.h"  
  2.   
  3. extern "C"void c_main2(int a, int b, int c)  
  4.   
  5. {  
  6.   
  7.      printf ("this is cppprogram\n!");  
  8.   
  9. }  
  10.   
  11.    
  12.   
  13. void main(void)  
  14.   
  15. {  
  16.   
  17.      c_main2(0,0,0);  
  18.   
  19.      return ;  
  20.   
  21. }  


结果:编译链接都通过。

通过objdump工具查看其生成的.obj文件,发现生成的c_main2()函数的汇编代码为:

[html]  view plain  copy  print ?
  1. 00000000<_c_main2>:  
  2.   
  3.    0:  55                      push   %ebp  
  4.   
  5.    1:  8b ec                   mov    %esp,%ebp  
  6.   
  7.    3:  83 ec 40                sub    $0x40,%es  
  8.   
  9.    6:  53                      push   %ebx  
  10.   
  11.    7:  56                      push   %esi  
  12.   
  13.    8:  57                      push   %edi  
  14.   
  15.    9:  8d 7d c0                lea    -0x40(%eb  
  16.   
  17.    c:  b9 10 00 00 00          mov    $0x10,%ec  
  18.   
  19.   11:  b8 cc cc cc cc          mov    $0xcccccc  
  20.   
  21.   16:  f3 ab                   rep stos%eax,%e  
  22.   
  23.   18:   6800 00 00 00          push   $0x0  
  24.   
  25.   1d:  e8 00 00 00 00          call   22 <_c_ma  
  26.   
  27.   22:  83 c4 04                add    $0x4,%esp  


虽然c_main2()函数在CPP文件中,但是在函数定义前加了extern “C”后,采用的是C标准编译方式,在函数名前加下划线,变成_c_main2()。该用GCC编译,结果一样,也使在函数名前加下划线。

3.4:使用场景

问题:那么什么情况下才需要使用extern “C”呢?

解答:

1、        由于系统内核一般是使用C语言来编写的,系统内核中用C语言实现了很多库。而上层应用程序有可能是用C++来开发,如果在内核库函数头文件中不用extern “C”来声明库函数的话,在编写C++应用程序时,包含库头文件,在C++文件链接时就会以C++标准来链接库的函数名,而在库文件实现时是用C来实现的,二者函数名不同,在链接时就会出现找不到函数的现象。

2、        在有些工程中,即包含.c文件有包含.cpp文件,如VC的工程。.cpp文件要调用.c文件中的函数时,需要extern “C” 声明.c文件中的函数,在CPP文件中让C++编译器使用C的标准来链接C文件中的函数

3.5:常用做法

在编写C代码的同时,为了可以被C++程序调用,通常会在C源代码对应的头文件中加入

[cpp]  view plain  copy  print ?
  1. #ifdef __cplusplus------------------------如果使用的是C++编译器  
  2. extern "C" {  
  3. #endif  
  4.   
  5.    
  6.   
  7. ……  
  8.   
  9. ……  
  10.   
  11. extern void c_main();------------------------------------外部函数接口声明  
  12.   
  13. #ifdef __cplusplus------------------------如果使用的是C++编译器  
  14. }  
  15. #endif   


这样做节省了维护代码的开销,在CPP代码中需要调用C中的接口时,直接包含C的头文件即可


当extern “C”的场合是当C程序调用C++的东西时:

按照如下步骤做即可

1. 在C++的.h文件中用extern “C”{}声明将被C程序使用的函数

2. 在C++的.cpp文件中实现上面的函数

3. 在.c文件中用extern声明要使用的C++函数

4. 使用即可

注意:切不可在.c文件中包含C++的.h文件,那样编译无法通过

上代码:

CPPClass.h中声明add函数

[cpp]  view plain  copy  print ?
  1. #ifndef __CPPClass_H__  
  2.   
  3. #define __CPPClass_H__  
  4.   
  5. extern "C"  
  6.   
  7. {  
  8.   
  9. int add(int a, int b) ;  
  10.   
  11. };  
  12.   
  13. #endif // end __CPPClass_H__  



CPPClass.cpp实现add函数
[cpp]  view plain  copy  print ?
  1. #include "CPPClass.h"  
  2.   
  3. int add(int a, int b)  
  4.   
  5. {  
  6.   
  7. return a + b ;  
  8.   
  9. }  
  10.   
  11. main.c 内容如下  
  12.   
  13. #include <stdio.h>  
  14.   
  15. //#include "CPPClass.h" // 不要包含头文件,否则编译不过  
  16.   
  17. extern int add(int a, int b) ; // 只需显示声明要调用的函数即可  
  18.   
  19. int main(void)  
  20.   
  21. {  
  22.   
  23. int result = add(1, 2) ; //使用函数  
  24.   
  25. printf("%d", result) ;  
  26.   
  27. return 0 ;  
  28.   
  29. }  



本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

extern C 在c/c++中的使用 的相关文章

  • c++11 正则表达式比 python 慢

    嗨我想了解为什么以下代码使用正则表达式进行分割字符串分割 include
  • OpenCV Visual Studio ntdll.dll

    我尝试在 Visual Studio 2013 上使用 OpenCV 2 4 10 创建一个项目 但由于以下异常 到目前为止我运气不佳 请建议帮助 TIA letstryitonemoretime exe Win32 Loaded C Us
  • gtest 和 gmock 有什么区别?

    我试图理解的目的google mock Google 的 C 模拟框架 https github com google googletest blob master googlemock README md 我已经与gtest较早 但我还是
  • 隐式方法组转换陷阱

    我想知道为什么给定代码的输出 在 LinqPad 中执行 void Main Compare1 Action Main Dump Compare2 Main Dump bool Compare1 Delegate x return x Ac
  • 我们如何将数据从一个打开的表单传递到另一个打开的表单?

    winform中如何将数据从一个窗体传递到另一个打开的窗体 在 Windows 应用程序中 一个窗体打开另一个窗体 当我在父表单中输入一些数据时 这些数据将立即反映在另一个子表单中 这将如何发生 取决于你想要多花哨 最简单的方法就是直接调用
  • 使用静态类型代替变量

    当您的项目不使用命名空间时 有什么方法可以告诉编译器使用静态类型而不是变量吗 例如 我有一个名为 User 的类 它具有各种静态和非静态方法 假设调用了其中一个静态方法GetUser 我想称之为User GetUser 方法来自一个方法 该
  • Entity Framework 4.1 RC:Code First EntityTypeConfiguration 继承问题

    我尝试使用通用的 EntityTypeConfiguration 类来配置所有实体的主键 以便每个派生的配置类不会重复自身 我的所有实体都实现一个公共接口 IEntity 它表示每个实体必须有一个 int 类型的 Id 属性 我的配置基类如
  • 返回指向 std::vector 中的对象的 a

    我有一个关于返回对向量元素的引用的非常基本的问题 有一个向量vec存储类的实例Foo 我想访问这个向量中的一个元素 不想使用向量索引 我应该如何编码该方法getFoo here include
  • 正则表达式删除某些字符周围不需要的空格

    我正在尝试从 JavaScript 文件中删除一些不需要的空格 并在将文件发送到客户端之前使用 C 和 Regex 组合文件 我有一个JavascriptHandler处理 js 文件 效果很好 这是我用来 打包 JavaScript 的函
  • 控制器中的异常处理 (ASP.NET MVC)

    当您自己的代码抛出异常并从控制器中的操作调用时 应该如何处理 我看到很多最佳实践的例子 其中根本没有 try catch 语句 例如 从存储库访问数据 public ViewResult Index IList
  • 以标准用户身份打开默认浏览器 (C++)

    我目前正在使用 ShellExecute 打开 在用户浏览器中打开 URL 但在 Win7 和 Vista 中遇到了一些麻烦 因为该程序作为服务运行提升 当 ShellExecute 打开浏览器时 它似乎读取 本地管理员 配置文件而不是用户
  • 替换 JSON 中的转义字符

    我想用空格替换 JSON 字符串中的 字符 我怎样才能做到这一点 我发现从 JSON 字符串中删除所有转义字符的最简单 最好的方法是将字符串传递到正则表达式 Unescape 方法 此方法返回一个没有转义字符的新字符串 甚至删除了 n t
  • 获取给定EntityType的导航属性

    我在用VS2010 EF4 0 需要如下功能 private string GetNaviProps Type entityType eg typeof Employee NorthwindEntities en new Northwind
  • 在 ncurses 中使用退格键

    我设置了一个简单的 ncurses 程序 它使用 getch 一次读取一个字符并将它们复制到缓冲区中 我遇到的问题是检测到按下退格键 这是相关代码 while buffer i c getch EOF i if c n break else
  • 为什么 std::ranges::filter_view 对象必须是非常量才能查询其元素?

    include
  • C 中的 N 依赖注入 - 比链接器定义的数组更好的方法?

    Given a 库模块 在下文中称为Runner 它作为可重复使用的组件 无需重新编译 即静态链接库 中应用程序分区架构的 而不是主分区 请注意 它仅包含main 出于演示目的 Given a set 顺序无关 调用的其他模块 对象Call
  • 需要使用 openssl 加密和解密文件的示例 C 代码

    我正在用 Linux C 编写代码 我需要使用以下命令来加密和解密文件 openssl 目前 我使用系统命令 des3 e nosalt k 0123456789012345 in inp file out out file 进行加密 使用
  • 使用 roslyn 扩展 C# 语法

    我试图在没有 else 情况的情况下实现 return if return value if 因为我只想在条件有效时返回或返回一个值 我知道 有if condition return or if condition return value
  • 在类中使用 std::chrono::high_resolution_clock 播种 std::mt19937 的正确方法是什么?

    首先 大家好 这是我在这里提出的第一个问题 所以我希望我没有搞砸 在写这篇文章之前我用谷歌搜索了很多 我对编码 C 很陌生 我正在自学 考虑到有人告诉我 只为任何随机引擎播种一次是一个很好的做法 我在这里可能是错的 什么是正确 最佳 更有效
  • 什么时候使用静态库需要头文件?

    如果我在 Linux 中用 C 创建一个静态库并生成 a 文件 我 或其他人 如何使用该库 例如 我的库定义了一个类 我认为仅仅提供 a 文件是不够的 还需要提供头文件 我如何知道 a 文件必须提供哪些头文件 例如 我是否需要提供我的库代码

随机推荐

  • UWSGI学习笔记

    uwsgi spooler可以用来实现Cron Task调度和非阻塞Task django相关安装包 uwsgidecorators 1 1 0 uwsgi tasks 0 6 4
  • c语言冒泡法对10个整数由大到小排序,用冒泡法对10个整数排序

    公告 为响应国家净网行动 部分内容已经删除 感谢读者理解 话题 用冒泡法对10个整数排序 10个整数用scanf函数输入回答 举了例 一个数组 3 2 5 1 4从小到大排序从左侧开始 逐对比较32 3 2的位置 数组变为2 3 5 1 4
  • git修改仓库名次之后,本地仓库重定向问题

    在github网页中更改了项目的名次 再次推送的时候报这样的错误fatal repository https xxx git not founds 使用下面的命令将推送的远程仓库重定向 git remote set url origin u
  • 数据压缩与管理:掌握Linux VDO和LVM的力量

    1 逻辑卷 LVM Logical Volume Management 动态的为服务器磁盘添加空间 而不会影响原磁盘的数据 也不需要对原始磁盘重新分区 1 1 LVM介绍 以下是LVM的示意图 我们拿到一块硬盘后首先对齐进行划分分区 也就得
  • [免签约]微信+支付宝个人收款解决方案

    方案原理 使用一台闲置的安卓手机专门用来做收款 收到付款时手机会有通知提示 对该通知进行监控 监控到后发送数据到服务器 服务器根据订单情况支付情况判断是否成功完成一轮下单支付操作 如果成功则自动发货 具体实现流程 网页前端展示商品 用户浏览
  • 华容道html源码,华容道(项目源代码)

    实例简介 Java华容道游戏完整代码 添加了图片与音效 设置了三个关卡 有注释 实例截图 核心代码 华容道 项目源代码 华容道 bin HuaRong About class BackgroundPanel class HuaRong 1
  • 学习PySOT避坑指南

    PySOT是商汤 SenseTime视频智能研究团队 开源的目标跟踪库 实现了最新的单目标跟踪算法 主要包含 SiamRPN SiamMask 使用Python编写的 基于Pytorch深度学习框架 该软件系统还包含了评估跟踪算法的Pyth
  • Java生成6位随机码(大小写+数字)

    char sources new char a b c d e f g h i j k l m n
  • 【Taro】微信小程序隐私协议改造

    微信要求小程序开发者在2023 9 15日前将小程序中调用获取用户隐私api的接口时 都必须要先让用户授权 如果用户拒绝授权 那么小程序的对应接口或组件将直接禁用 那么首先 请将微信小程序开发者工具 详情 本地设置 基础调试库 切换至2 3
  • QT实现用户登录功能

    功能 1 提供登录界面 客户端 2 服务器端用数据库来存储用户名和密码 3 注册时客户端将注册信息发送给服务器端 并进行验证 如果注册名可用 添加进数据库并返回客户端添加成功信息 4 登录时客户端将登录信息发送给服务器端进行验证 服务端返回
  • Ubuntu14.04下配置CGAL+boost+QT+Suitesparse

    这两天突然间想把以前在linux在没有调通的程序给调通 这个程序需要用到CGAL和Suitesparse 稀疏矩阵计算 大家上网查哈 而CGAL又依赖于boost 和QT 所以总共需要安装boost QT suitesparse和CGAL
  • java二维数组的创建,java二维数组创建方法

    java动态创建二维数组 从零学java笔录 第31篇 图解二位数组在内存中存储 java二维数组动态赋值 java二维数组创建方法 二维数组的定义 type arrayName type arrayName Java 二维数组的声明 初始
  • 数据可视化入门学习——Jupyter Notebook 和绘图有关的几个魔术指令

    数据可视化 Jupyter Notebook 和绘图有关的几个魔术指令 matplotlib inline 这是默认的模式 输出的图片是静态的 matplotlib auto 在这个模式下会弹出一个单独 的绘图窗口 和在pycharm中一样
  • MyBatis枚举映射类讨论

    前言 本篇需要对于MyBatis有一定的认识 而且只是针对于TypeHandler接口来讨论 暂不讨论其他方面的问题 TypeHandler概叙 TypeHandler是MyBatis设计的一个用于参数的接口 你们会不会很好奇MyBatis
  • 【error】 java.net.MalformedURLException: no protocol,未指定通信协议

    目录 1 报错信息 2 报错原因 3 处理方法 1 报错信息 在通过 IP 地址及端口号调用远程方法时 报错信息如下 java net MalformedURLException no protocol 由 no protocol 可知 系
  • 海凌科7621开发板适配新版openwrt

    最近在海凌科买了一块7621的开发板 flash是32M的 ddram是256M的 性价比感觉不错 海凌科提供的openwrt是比较旧的版本 在openwrt最新的19 07版本里已有的硬件都有一定的差距 因此修改一下相关配置 可以用ope
  • PHP如何使用循环语句?用法详细指南

    像任何其他语言一样 PHP中的循环用于多次执行一条语句或一段语句 直到满足特定条件为止 这有助于用户节省多次编写同一代码的时间和精力 PHP支持四种类型的循环技术 for循环 while循环 循环执行 foreach循环 现在让我们详细了解
  • 包装类自动装箱和拆箱原理

    包装类的自动装箱和自动拆箱 包装类的自动装箱和拆箱是JDK1 5的新特性 一 首先 了解自动装箱的过程 有两种自动装箱过程 第一种 128 127 之内 调用相应包装类的valueOf 例如 Integer i 12 Integer a 2
  • L2-016 愿天下有情人都是失散多年的兄妹 (25 分)

    题目 题目链接 题解 DFS 孩子向父母方向连边 将孩子视为根节点 首先判断输入两个人的性别 如果不同再分别以二者为起点进行dfs 前者五服之内的亲属都标记一下 以后者为起点dfs 如果遇到了标记的人 那么说明五服之内存在公共祖先 不可以结
  • extern C 在c/c++中的使用

    http blog csdn net jscese article details 37821961 1 问题定义 在研究操作系统源代码或者在嵌入式系统中编写程序时 经常会发现下面这种用法 cpp view plain copy print