extern、关于C++的变量和类的声明和定义

extern

参考:extern声明变量详解

变量的声明:

int data;         // 这样既声明了data同时也定义了data
extern int data; // 只声明而不定义

函数的声明:

void hello();           // 函数的声明
extern void hello();    // 也是函数的声明,和void hello(); 一模一样。 参考:https://blog.csdn.net/weixin_38145317/article/details/86496041
                        // extern void hello(); 仅仅是暗示这个函数可能在别的源文件里定义。
                        // 如果在函数定义的地方带有关键字extern,表示该函数会提供给外部文件使用,
                        // 其实有些编译器是默认每个函数都是extern类型的,反之是static类型。参考:https://developer.aliyun.com/article/638079

extern声明全局变量:

  • 头文件中不允许定义全局变量,因为当头文件中定义了全局变量A,则每一个包含了头文件的源文件中会定义一次全局变量A,使得整个代码空间中多次定义了此全局变量A,编译时会出现重定义的错误。
  • 一般会在头文件中使用extern对全局变量进行声明,这样其他包含此头文件的源文件就可以使用此全局变量。头文件中只进行了声明,所以必须有且仅有一个源文件中对全局变量进行定义。

使用变量之前必须声明,声明可以有多次,而定义只能有一次。

extern "C"

extern“C”的作用(最重点)

  • extern "C"的真实目的是实现类C和C++的混合编程。extern “C”是由C++提供的一个连接交换指定符号,用于告诉C++这段代码是C函数。extern “C”后面的函数不使用的C++的名字修饰,而是用C。这是因为C++编译后库中函数名会变得很长,与C生成的不一致,造成C++不能直接调用C函数。
  • C++语言支持函数重载,C语言不支持函数重载。函数被C++编译后在库中的名字与C语言的不同。假设某个函数的原型为:void foo(int x, int y);该函数被C编译器编译后在库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字。C++提供了C连接交换指定符号extern“C”来解决名字匹配问题。
  • 被extern "C"限定的函数或变量是extern类型的;extern是C/C++语言中表明函数和全局变量作用范围(可见性)的关键字,该关键字告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。被extern "C"修饰的变量和函数是按照C语言方式编译和连接的。
  • 与extern对应的关键字是static,被它修饰的全局变量和函数只能在本模块中使用。因此,一个函数或变量只可能被本模块使用时,其不可能被extern “C”修饰。

extern "C":让此c++代码按照c语言的方式编译。这应该就导致了此c++代码中的函数不能进行重载操作。

c++代码中使用c库

// cheader.h
#ifndef _C_HEADER_
#define _C_HEADER_
 
#ifdef __cplusplus
extern "C" {
#endif
 
#include <stdio.h>
#include <stdlib.h>
int add(int a,int b);
 
 
#ifdef __cplusplus
}
#endif
 
#endif
 
// cfunc.c
//#include "header.h"
int add(int a,int b)
{
    return a+b;
}
//main.cpp
#include <iostream>
#include "cheader.h"
using namespace std;
int main()
{
 
    int a,b=0;
    b= add(2,3); 
    cout<<b<<endl;
    return 0;
}

编译:

gcc -c cfunc.c -o libadd.a  # 生成c静态库
g++ main.cpp libadd.a       # C++中使用c静态库。

如果cheader.h中没有使用extern "C",上述编译过程会出错。

c代码中使用c++库

// cheader.h头文件
#ifndef _C_HEADER_
#define _C_HEADER_
 
#ifdef __cplusplus
extern "C" {
#endif
 
 #include <stdio.h>
#include <stdlib.h>
 
 int sub(int a,int b);
 
#ifdef __cplusplus
}
#endif
#endif
//cppsub.cpp
#include "cheader.h"
int sub(int a,int b)
{
	return a-b;
}
/*但是如果将头文件的那一行注释掉,也会在连接时出错,因为在头文件中已经说明使用C语言的方式编译,但是不说明这一点,会使用C++编译方式进行
*/
//cmain.c
 #include "cheader.h"
int main()
{
     int a=0,b=0;
     b = sub(2,3);
     printf("b is %d\r\n",b);
     return 0;
}

__cplusplus的作用:如果是C++文件(*.cpp)后缀,则使用extern “C”。
【这里为什么写了两个#ifdef __cplusplus……#endif??】答:cmain.c中使用#include "cheader.h"可以将#include <stdio.h>#include <stdlib.h>包含进来。从这点我们可以知道,两个#ifdef __cplusplus……#endif使得#ifdef __cplusplus……#endif并没有作用到#include <stdio.h>#include <stdlib.h>上。

编译:

g++ -c cppsub.cpp -o libsub.a  # 生成c静态库
gcc cmain.c libsub.a       # C++中使用c静态库。

如果cheader.h中没有使用extern "C",上述编译过程会出错。

参考自:C/C++混合编程--extern “C”

类的声明和定义

参考:关于C++的变量和类的声明和定义

定义一个类时,对于其中的数据成员,不论有无默认值,也不论是static还是非static的,我们只是描述了一个类,注意,仅仅是描述了类,也即,我们只知道它含有哪些类型,如果还定义了函数成员,我们还描述了这种类型的操作。所以类中的成员变量都只是被声明了,并未被定义。

当类中包含static修饰的成员变量,那么就必须在源文件中对static变量进行定义,如下:

// test.h 
#pragma once

class A{
public:
    static int a; // 声明static成员变量
  ...
};


// test.cpp
#include"test.h" 

int A::a; // 定义static成员变量

int main(){
      
    return 0;
}
posted @ 2022-10-14 14:36  好人~  阅读(727)  评论(0编辑  收藏  举报