美文网首页
C++基础语法-重载、extern

C++基础语法-重载、extern

作者: 码无不至 | 来源:发表于2020-01-24 17:10 被阅读0次

函数重载

今天我们来深入学习下C++的基础语法函数重载。函数重载定义:只要函数名相同,参数个数不同,参数类型不同,参数顺序不同就构成C++的函数重载。其本质是编译器采用一种叫name mangling也叫name decoration的一种技术对函数名修饰装饰达到函数名唯一的的目的,它提供了在函数、结构体、类、或其它的数据类型的名字中编码附加信息一种方法,用于从编译器中向链接器传递更多语义信息。先来看一下C++函数重载的列子:

#include <stdio.h>
#include <iostream>
using namespace std;
void print() {
    cout<<"print() "<
}
void print(int a) {
    cout<<"print(int a) "<< a << endl
}
void print(long a) {
   cout<<"print(long a) "<< a << endl
}
void print(double a) {
   cout<<"print(double a) "<< a << endl
}
int main(int argc,const char* argv[]) {
    print(); //  __Z5printv:
    print(10);//  __Z5printi:
    print(10l);// __Z5printl:
    print(10.1);//__Z5printd:
    return 0;
}

由于C不支持重载,但是C++经过编译器name mangling技术,函数名字已经被修饰成具有唯一函数名的函数,然后各自分别调用,每个编译器修饰的结果不一样,我这里采用的编译器是Apple Clang。下面再列举一个维基百科上面name mangling的应用,代码如下:

#include <stdio.h>
#include <iostream>
using namespace std;
namespace wikipedia
{
    class article
    {
    public:
        std::string format (void)
        {
            return "";
        }
        /* = __ZN9wikipedia7article6formatEv */
        
        bool print_to (std::ostream&)
        {
            return true;
        }
        /* = __ZN9wikipedia7article8print_toERSo */
        
        class wikilink
        {
        public:
            wikilink (std::string const& name){}
            /* = __ZN9wikipedia7article8wikilinkC1ERKSs */
        };
    };
}
int main(int argc, const char * argv[]) {
    wikipedia::article art;
    art.format();
    art.print_to(cout);
    wikipedia::article::wikilink link("link_name");
    return 0;
}

编译以上代码通过相关工具查看其二进制代码,我这里是采用Hopper Disassembler工具,定义在类内部的成员函数通过name mangling都进行了转换,转换后的函数名保持唯一(查看函数代码注释),以上述转换后的函数__ZN9wikipedia7article6formatEv为例:以__Z开头,N表示命名空间,紧接着9是命名空间的长度,再跟上命名空间,7是类的类名长度,再跟上类名,6是类成员函数名字长度,再跟上函数名,E表示结束符,v表示函数返回值。这样不同的类的不同的函数通过编译器都被唯一确定,程序运行的时候找到的函数地址都是唯一。正向开发的时候,我们基本不用管函数最终转换成了哪个函数名,但是逆向的时候,我们只能拿到别人二进制文件,看到的很多函数名字都是通过name mangling之后的函数名,我们可以借助相关工具c++filt终端执行还原函数名:

c++filt __ZN9wikipedia7article8wikilinkC1ERKSs
wikipedia::article::wikilink::wikilink(std::string const&)

extern "C"

C++文件如果要调用C语言文件,经常我们要制定C++按照C的方式编译,通常项目C文件要被C++和C都可以调用,C++才有exten "C",C没有extern "C"的定义,C++中自己定义了个宏__cplusplus。鉴于上述特征,可以在要调用的C头文件函数声明的时候做一个判断处理,同时支持C++和C的调用,示例代码如下:

#ifdef __cplusplus
extern "C"{
#endif
//此函数既可以被C调用也可以被C++调用
int print(void);
#ifdef __cplusplus
}
#endif

关于extern在C语言中的用法这里做一个补充,extern关键字一般用于声明变量或者函数,告诉程序如何去找到它,不分配内存,可以多次声明,而定义会分配内存且只能定义一次。下面我们来分别看看函数和变量的extern用法:
1.函数:函数的extern一般在声明或者定义编译器会隐式声明,我们自己不用加,比如我们这样写:

int foo(int arg1, char arg2);

编译器会这样翻译:

 extern int foo(int arg1, char arg2);

加了exten后,这个函数在整个程序中可见,只要提供了这个函数声明,可以在其它地方使用或者调用,编译器会自动去找函数的定义并且进行编译。
2.变量;变量跟函数exten用法不太一样,变量的声明和定义如下:

int age;       //既声明又定义,编译器默认赋值为0
int age = 100; //既声明又定义,手动赋值为100
extern age; //只声明,编译器会去找相关定义拿到相关的值
extern int age = 100;  //显示声明和定义,手动赋值为100

参考文献:
https://en.wikipedia.org/wiki/Name_mangling
https://www.geeksforgeeks.org/understanding-extern-keyword-in-c/

相关文章

  • C++基础语法-重载、extern

    函数重载 今天我们来深入学习下C++的基础语法函数重载。函数重载定义:只要函数名相同,参数个数不同,参数类型不同,...

  • C++ 学习(2) ---- 基本语法介绍

    C++ 基本语法(2) C++基础语法说明模板NA运算符重载NA强制类型转换static_cast,const_c...

  • C/C++常见问题记录

    C/C++ 语法 extern “C”的作用详解[https://www.cnblogs.com/xiangtin...

  • C++基础-(重载)

    C++基础 重载 哪些运算符可以被重载:::,.,->,*,?:不能被重载 重载操作符的标志(operator) ...

  • c和c++的关系

    1 在c++中调用被c编译器编译后的函数,为什么要加extern "c"; 因为c++语言支持函数重载,而c语言不...

  • C++类的运算符重载

    C++类运算符重载是一种方便的语法,例如可以执行两个类相加 类的运算符重载语法如下

  • C/C++编译区别

    为了支持函数的重载,C++对全局函数的处理方式与C有明显的不同。 extern "C" { C代码 } 被exte...

  • c++ 入门 - 函数重载,extern

    c++的输入输出 输入 输出 例子 extern extern 修饰符可用于c++中调用c函数的调用规范比如在c+...

  • 01.函数重载,extern C,默认函数

    一.函数重载 7.1 二.extern "C" 2.3 26.1

  • 第十二章 下标

    c++下标通过重载操作符operator []实现,swift的下标语法: subscript(index: In...

网友评论

      本文标题:C++基础语法-重载、extern

      本文链接:https://www.haomeiwen.com/subject/oyncthtx.html