一、extern 做变量声明
声明 extern 关键字做全局变量和全局函数,可以使它们能够跨文件访问。
extern是C/C++语言中表明函数和全局变量作用范围的关键字,该关键字告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。
通常,在本模块的头文件中对本模块提供给其它模块引用的函数或变量以关键字extern声明。
说明:下面的示例都是使用VScode进行编辑,使用mingw32进行编译,由于混用C C++,对于.c文件,先使用gcc -c *.c 将对应的 *.c 文件编译为 *.o文件;同样,使用 g++ -c *.cpp 将 .cpp文件编译为 .o 文件,然后在使用 g++ *.o -o run,链接所有生成的 .o 文件,生成 run.exe 可执行文件。
示例如下:
/**
* origin.h
*/
#include <stdio.h>
extern int g_size; // 全局变量声明
/**
* origin.c
*/
#include <stdio.h>
int g_size = 100; // 全局变量定义
int print_size(void) // 全局函数,默认就是extern的
{
printf("gsize : %d\n", g_size);
return 0;
}
/**
* user.c 引用origin.h中声明的全局变量和origin.c中的全局函数
*/
#include <stdio.h>
#include "origin.h"
extern int print_size(void); // 函数声明,表示使用其它文件定义的全局函数
int main(void)
{
print_size();
printf("main gsize: %d\n", g_size);
return 0;
}
声明和定义的区别:
声明:extern int a; // 属于声明,未分配内存空间
定义:extern int a = 10; // 属于定义,初始化并分配了内存空间
注意:声明可以拷贝n次,但是只能定义一次,否则链接会产生重复定义错误
如果在一个文件里定义了char g_str[] = “hello,world”; 在另一个文件中必须使用extern char g_str[]; 来声明,不能使用extern char *g_str; 来声明,extern是严格的声明
二、extern "C"
extern “C” 包含双重含义:首先,被它修饰的目标是”extern”的;其次,被他修饰的目标是 “C” 的
被 extern “C” 限定的函数或变量是extern类型的
因为C++支持函数重载,而C语言不支持函数重载,因此,C++函数名和C函数名编译后的结果是不同的。C++编译后的函数名是很据函数名和参数类型决定的,而C是根据函数名决定的。
例如:
int add (int x, int y)
如果是C,则编译后的函数名可能为_Add,如果是C++,编译后的函数名可能为_Add_Int_Int,这里只是举例说明。为了解决不同编译器对函数名采用不同的编译方法,需要使用extern "C"限定是否采用C风格的编译器,以确保函数调用时找不到对应的函数。
extern "C" 惯用方法:
1. C++ 中使用 C:
在C++中引用C语言中的函数和变量,在包含C语言头文件(如example.h)时,需要进行如下处理:
extern “C”{
#include “example.h”
}
在C语言的头文件中,对其外部函数只能指定为extern类型,C语言不支持extern “C”声明,在.c文件中使用extern “C”时会出现编译时语法错误.
示例如下:
/**
* c_file.h 声明writes函数,由cplus_file.cpp调用
*/
#ifndef _C_FILE_H_
#define _C_FILE_H_
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
extern void writes(const char* array);
#ifdef __cplusplus
}
#endif
#endif
/**
* c_file.c
*/
#include "c_file.h"
#include <string.h>
extern void writes(const char* array)
{
char arr[] = {"Hello, world!"};
printf("%s", arr);
}
/**
* cplus_file.h 定义c++方法writeStr(),该方法中调用C方法writes()
*/
#ifndef _CPLUS_FILE_H
#define _CPLUS_FILE_H
#include <string>
using namespace std;
void writeStr(string str);
#endif
/**
* cplus_file.cpp
*/
#include <iostream>
// 如果c_file.h中未使用extern "C",也可以在引入c_file.h头文件是将其使用extern "C"进行包含
// extern "C" {
#include "c_file.h"
// };
#include "cplus_file.h"
using namespace std;
int main(void)
{
string str("Nice to meet you!");
writeStr(str);
return 0;
}
void writeStr(string str)
{
cout << str << endl;
writes(str.c_str());
}
2. C中使用C++:
在C中引用C++语言中的函数和变量时,C++的头文件需要添加extern “C”,但是在C语言中,不能直接引用声明了extern “C”的C++头文件,应该仅在C文件中将C++文件中定义了extern “C”的函数 声明为extern类型。
示例如下:
/**
* c_file.c
*/
#include "cpp_file.h"
int add(int x, int y)
{
return x + y;
}
/**
* cpp_file.h 声明 c_file.c中调用的函数
*/
#ifndef _CPP_FILE_H_
#define _CPP_FILE_H_
extern "C" int add(int x, int y); // 声明函数,该函数按照C语言的风格进行编译
#endif
/**
* cpp_file.cpp
*/
#include "cpp_file.h"
int add(int x, int y)
{
return x + y;
}