• 为什么c++支持函数重载,c语言不支持



    前言

    为什么c++可以支持函数重载,而c语言不支持,这其实是因为c++和c在链接时对函数名修饰规则的不同。


    一、c++可以支持函数重载,而c语言不支持

    1、c语言的函数名修饰规则

    我们知道.c文件经过编译器编译为可执行程序需要经过以下的步骤。
    在这里插入图片描述
    其中在链接过程中,当test.c中调用了在add.c中定义的Add函数时,在进行汇编后,链接前。test.obj和add.obj文件中都生成了自己的符号表,我们可以看到test.obj目标文件的符号表中没有Add的函数地址,这是因为Add是在add.c中定义的,所以Add的地址在add.obj中,那么这种情况该怎么办呢?所以链接阶段就是专门处理这种问题,链接器看到test…obj中调用Add,但是符号表中没有Add的地址,就会到add.obj的符号表中找Add的地址,然后链接到一起。
    在这里插入图片描述
    那么链接时,面对Add函数,链接器会使用哪个名字去找呢?即链接器如果要找Add函数真正的地址,会直接拿Add这个名字去每个.obj目标文件中去找该函数的地址吗?这个问题其实就是为什么c++可以函数重载而c语言不可以函数重载的原因。结论就是c语言在编译后会直接按函数名去找该函数地址,而c++会使用函数名修饰规则为每个函数重新命名。
    即例如如果在c语言写如下代码,定义了两个函数名相同但形参不同的函数Add时,在汇编后形成.obj的目标文件时,符号表中直接以Add函数的名字为符号。这样在链接时,链接器会直接拿Add这个函数名去每个.obj目标文件中找Add函数地址,然后就会发现有两个Add函数的地址,这样就会不知道链接哪一个Add函数地址,所以就会出现错误。

    #include
    int Add(int x, int y)
    {
    	return x + y;
    }
    
    double Add(double x, double y)
    {
    	return x + y;
    }
    
    int main()
    {
    	printf("%d\n", Add(1, 2));
    	printf("%d\n", Add(2.3, 3.2));
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    现在我们在Linux系统下使用gcc编译器来编译test.c文件生成testc可执行文件。
    在这里插入图片描述

    在这里插入图片描述
    objdump命令是Linux下的反汇编目标文件或者可执行文件的命令,我们使用objdump命令来查看testc的反汇编目标文件。我们可以看到在反汇编目标文件中Add函数和func函数没有进行函数名修饰,而是直接显示出来函数的实际名字。
    在这里插入图片描述
    在这里插入图片描述

    2、c++的函数名修饰规则

    而在c++中定义了两个函数名相同但形参不同的函数Add时,在汇编后形成.obj的目标文件时,在符号表中不会直接以Add函数的名字为符号,而是会根据函数的参数等不同而对函数名加以修饰。这样在链接时,链接器会拿修饰过的函数名去每个.obj目标文件中找该函数地址,这样就避免了一个函数名有两个函数地址。所以c++中可以进行函数重载。
    例如我们使用下面的代码。然后使用g++编译器将test.c按照c++的语法来进行编译和链接形成可执行程序testcpp。
    在这里插入图片描述
    在这里插入图片描述
    然后使用objdump命令查看可执行程序testcpp的反汇编文件。可以看到在testcpp的反汇编文件中Add函数名经过g++编译器的函数名修饰规则后变为Addii,而不是原来的函数名Add了。这样链接器就不会不知道找哪一个函数的地址了。
    在这里插入图片描述
    在这里插入图片描述
    我们写一个函数重载的c++程序通过g++编译器编译过后,观察可执行文件的反汇编文件。可以看到根据Add函数的参数不同,Add函数经过函数名修饰规则产生的函数名也不同,这就是c++可以实现函数重载的原因。
    所以得出结论在linux下,采用g++编译完成后,函数名字的修饰发生改变,编译器将函数参数类型信息添加到修改后的名字中。

    在这里插入图片描述
    在这里插入图片描述

    3、总结

    经过上面的分析就理解了C语言没办法支持重载,因为同名函数没办法区分。而C++是通过函数修饰规则来区分,只要参数不同,修饰出来的名字就不一样,就支持了重载。如果两个函数函数名和参数是一样的,返回值不同是不构成重载的,因为调用时编译器没办法区分。

    二、c++程序调用c写的静态库

    具体实现

    如果我们写了一个c++的项目,但是使用了一个c语言写的静态库,那我们该怎样用这个c的静态库呢。例如我们之前用c语言实现的栈的操作,然后此时我们想要在c++中调用这些栈操作,此时我们就需要做一些操作,然后才能使c++中可以使用这些c语言实现的库。
    我们先将使用c语言实现的栈的操作打包为静态库。
    在这里插入图片描述在这里插入图片描述
    然后在Debug文件夹下可以看到打包好的静态库,即.lib文件。
    在这里插入图片描述
    此时将该.lib文件和stack.h这个头文件都拷贝到我们的c++项目中。
    在这里插入图片描述
    然后在c++项目中打开属性进行一些c++项目静态库引入的配置。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    此时该c++项目中就引入了test08.lib静态库,此时需要引入该静态库的头文件。
    在这里插入图片描述
    但是当我们运行时,会发现报出了错误。这是因为上面我们所讲的,c++和c语言在链接时,c语言在函数名修饰时是直接将函数名作为标识,而c++在函数名修饰时,会加上该函数的参数,共同组成该函数的标识。所以此时当c++调用c语言写的静态库时,在链接时会发现函数名修饰不一样,即c语言是按c语言的函数名修饰规则编译的这些函数名,而c++是按c++的函数名修饰规则编译这些函数名,所以在链接时会找不到这些函数,才会报出无法解析函数的错误。
    在这里插入图片描述
    此时需要告诉c++编译器,这个stack.h头文件中实现的方法都是使用c语言实现的,当编译时要按照c语言的函数名修饰规则编译,这样链接时才可以查到到这些函数,此时程序才不报错。
    在这里插入图片描述

    总结

    这就是c++项目引用c语言实现的静态库。因为c++兼容c语法,所以静态库中的语法c++都兼容,但是c++和c语言在编译时对函数名修饰的规则不一样,所以需要做一些处理,以便c++在调用该静态库的方法时,可以找到这些方法。

    三、c程序调用c++写的静态库

    具体实现

    c语言项目也可以调用c++写的静态库。不过也需要做一些处理。
    此时先将上面的栈用c++的编译器打包成静态库,即将.c文件改为.cpp文件。
    在这里插入图片描述
    然后将打包好的静态库和头文件都拷贝到c项目的目录中。
    在这里插入图片描述
    此时运行c项目也会报错,错误原因还是因为c++和c语言在编译时函数名修饰规则不同,所以在链接时才查找不到对应函数。
    在这里插入图片描述
    此时在c++项目的.h文件中加入extern “C” {}语句,即告诉编译器在生成这些函数时,按照c的函数名修改来生成。此时会发现报错,这是因为extern “C” {}为c++语言,所以在c项目中会报错。
    在这里插入图片描述
    这时就要加上条件编译来判断了。即如果为c++文件,就加上c++的语法,如果不是c++文件,就不加上c++的语法。
    在这里插入图片描述
    在这里插入图片描述

    总结

    虽然c项目可以使用c++写的静态库,但是因为c语言不兼容c++语法,所以该c++库中不能出现c++的一些语法,不然c语言项目识别不了这些c++语法,就会报错。

  • 相关阅读:
    Unity与IOS⭐Unity接入IOS SDK的流程图
    AWK语言第二版 2.3转换
    新手如何练习SQL?|掌握
    C语言中关于printf()输出的时候的一个出栈入栈问题
    redis使用学习笔记
    动态规划:01背包(Dynamic Programming)
    Java工具库Guava的不可变集合和新集合类型Multiset、Multimap、BiMap、RangeSet、RangeMap等的使用示例
    前端面试练习24.3.16
    【云原生 | Kubernetes 系列】K8s 实战 如何给应用注入数据 II 将pod数据传递给容器
    【PostgreSQL 15】PostgreSQL 15对UNIQUE和NULL的改进
  • 原文地址:https://blog.csdn.net/dong132697/article/details/132710245