C++学习笔记(二)——extern “C“ 用法详解

简介: C++学习笔记(二)——extern “C“ 用法详解

extern "C"是什么?


前面一章节简单的介绍了extern "C"的基本概念就是有时候在C++工程中可能需要将某些函数按照C的风格来编译,在函数前加extern "C",意思是告诉编译器,将该函数按照C语言规则来编译。

这一章将进行详细介绍其用法,为了更好地了解,下面将举个OJ题实例:

使用场景:


题目: 有效括号

image.png

解这道题需要我们自己写个栈,但是这里为了讲解extern "C"的用法,将把栈一系列操作写好编译到静态库中然后进行调用:

bool isValid(char* s) {
    ST st;
    StackInit(&st);
    int i = 0;
    while (s[i])
    {
        //左括号就插入
        if (s[i] == '(')
        {
            StackPush(&st, ')');
        }
        else if (s[i] == '{')
        {
            StackPush(&st, '}');
        }
        else if (s[i] == '[')
        {
            StackPush(&st, ']');
        }
        else
        {
            //if (st.empty())//栈里为空,且现在为右括号就直接返回false
               // return false;
            if (!StackEmpty(&st) && StackTop(&st) == s[i])
            {
                StackPop(&st);
            }
            else
            {
                StackDestroy(&st);
                return false;
            }
        }
        i++;
    }
    if (StackEmpty(&st))
    {
        StackDestroy(&st);
        return true;
    }
    else
    {
        StackDestroy(&st);
        return false;
    }
}
int main()
{
    char str1[] = "{[]}";
    char str2[] = "([)]";
    printf("%d\n", isValid(str1));
    printf("%d\n", isValid(str2));
    return 0;
}

静态库的创建


静态库,目前我还不太清楚,后面会在linux中跟大家一起探讨,现在咱们就理解成别人写好给你用的,被编译好的程序.

先创建一个空项目,把之前写的栈放进去,然后打开项目属性,把.exe属性改为静态库(lib)属性即可:

image.png

编译后运行,静态库就完成了。

622103e0c5ed46bc89a5c766bdaa4b46.png

C程序调用C写的静态库,显然没有任何阻碍可以正常操作,同理C++程序调用C++写的静态库也不会有问题,这里就不带大家一起操作了。下面我将讲解C++调用C写的静态库 和C调用C++写的静态库的操作。

C++程序调用C写的静态库


调用库之前我们要做如下操作:

第一步:

06fcb42b63444bcebd9c8c9b4babd349.png

第二步:

eaaf0f5e8d0a4b068204aad31c535643.png

然后下面就可以操作起来了.

C++调用C写的静态库

首先需要包含头文件(创建栈静态库的路径)

#include "../stack/stack/stack.h"

.表示当前目录

..表示上一层目录

然后我们来运行一下:

ff93e9efc7184aeca49d100c094e3c9a.png

这里出现了链接错误,通过前一章函数重载的学习我们很快会发现问题的所在:C++修饰函数名的方法与C修饰函数名方法不一样,导致在静态库找不到这些函数,因此我们引出了:extern "C"

image.png

这段代码的意思是:告诉编译器在调用这个静态库时,调用函数使用C的风格去调用(即调用函数时不使用函数名修饰规则)

这样我们就可以正常运行了:

image.png

C程序调用C++写的静态库


首先我们把先前C++的项目后缀改成 .c,把静态库的c文件改成cpp,我们试着反着来调用,会发生什么。

image.png

image.png

image.png

很显然C程序无法调用C++静态库中函数名被修饰的函数

所以我们需要在C++静态库中使用extern "C",因为c程序中无法识别extern "c"

我们这里介绍两种方法来修改:

第一种:

#ifdef __cplusplus
extern "C"
{
#endif
  //初始化栈
  void StackInit(Stack* ps);
  //销毁栈
  void StackDestroy(Stack* ps);
  //压栈
  void StackPush(Stack* ps, STDatatype x);
  //出栈
  void StackPop(Stack* ps);
  //取出栈顶元素
  STDatatype StackTop(Stack* ps);
  //栈的大小
  int StackSize(Stack* ps);
  //判断栈是否为空
  bool StackEmpty(Stack* ps);
#ifdef __cplusplus
}
#endif

第二种:

#ifdef __cplusplus
#define EXTERN_C extern "C"
#else
#define EXTERN_C
#endif
//初始化栈
EXTERN_C void StackInit(Stack* ps);
//销毁栈
EXTERN_C void StackDestroy(Stack* ps);
//压栈
EXTERN_C void StackPush(Stack* ps, STDatatype x);
//出栈
EXTERN_C void StackPop(Stack* ps);
//取出栈顶元素
EXTERN_C STDatatype StackTop(Stack* ps);
//栈的大小
EXTERN_C int StackSize(Stack* ps);
//判断栈是否为空
EXTERN_C bool StackEmpty(Stack* ps);

现在就可以正常运行了:

image.png

以上是extern "C" 的详细操作,有不足的地方或者对代码有更好的见解,欢迎评论区留言共同商讨,共同进步!!

image.png

相关文章
|
3月前
|
存储 编译器 C语言
详解C/C++中的static和extern
本文详解了C/C++中`static`和`extern`关键字的用法和区别,通过具体代码示例说明了在不同情境下如何正确使用这两个关键字,以及`extern "C"`在C++中用于兼容C语言库的特殊作用。
109 4
详解C/C++中的static和extern
|
9天前
|
存储 安全 编译器
第二问:C++中const用法详解
`const` 是 C++ 中用于定义常量的关键字,主要作用是防止值被修改。它可以修饰变量、指针、函数参数、返回值、类成员等,确保数据的不可变性。`const` 的常见用法包括:
48 0
|
1月前
|
存储 C++ 容器
【C++】map、set基本用法
本文介绍了C++ STL中的`map`和`set`两种关联容器。`map`用于存储键值对,每个键唯一;而`set`存储唯一元素,不包含值。两者均基于红黑树实现,支持高效的查找、插入和删除操作。文中详细列举了它们的构造方法、迭代器、容量检查、元素修改等常用接口,并简要对比了`map`与`set`的主要差异。此外,还介绍了允许重复元素的`multiset`和`multimap`。
30 3
【C++】map、set基本用法
|
4月前
|
C++
c++学习笔记07 结构体
C++结构体的详细学习笔记07,涵盖了结构体的定义、使用、数组、指针、嵌套、与函数的交互以及在结构体中使用const的示例和解释。
42 0
|
9天前
|
C++
第十三问:C++中静态变量的用法有哪些?
本文介绍了 C++ 中静态变量和函数的用法及原理。静态变量包括函数内的静态局部变量和类中的静态成员变量,前者在函数调用间保持值,后者属于类而非对象。静态函数不能访问非静态成员,但可以通过类名直接调用。静态链接使变量或函数仅在定义文件内可见,避免命名冲突。
22 0
|
3月前
|
安全 C语言 C++
C++学习笔记
C++学习笔记
|
4月前
|
编译器 C++ 容器
【C++】String常见函数用法
【C++】String常见函数用法
|
4月前
|
C++
【学习笔记】【C/C++】 c++字面值常量
【学习笔记】【C/C++】 c++字面值常量
46 1
|
4月前
|
编译器 C++
【C/C++学习笔记】C++声明与定义以及头文件与源文件的用途
【C/C++学习笔记】C++声明与定义以及头文件与源文件的用途
63 0
|
4月前
|
存储 C++
【C/C++学习笔记】string 类型的输入操作符和 getline 函数分别如何处理空白字符
【C/C++学习笔记】string 类型的输入操作符和 getline 函数分别如何处理空白字符
55 0