名字修饰(name Mangling)

在C/C++中,一个程序要运行起来,需要经历以下几个阶段:预处理、编译、汇编、链接。

Name Mangling是一种在编译过程中,将函数、变量的名称重新改编的机制,简单来说就是编译器为了区分各 个函数,将函数通过某种算法,重新修饰为一个全局唯一的名称。
C语言的名字修饰规则非常简单,只是在函数名字前面添加了下划线。比如,对于以下代码,在后链接时就 会出错:

int Add(int left, int right);int main()
{ Add(1, 2);
return ;
}

编译器报错:error LNK2019: 无法解析的外部符号 _Add,该符号在函数 _main 中被引用。
上述Add函数只给了声明没有给定义,因此在链接时就会报错,提示:在main函数中引用的Add函数找不到函 数体。从报错结果中可以看到,C语言只是简单的在函数名前添加下划线。因此当工程中存在相同函数名的函 数时,就会产生冲突。
具体例子看上篇博客有详细介绍。
由于C++要支持函数重载,命名空间等,使得其修饰规则比较复杂,不同编译器在底层的实现方式可能都有差 异。

int Add(int left, int right);int main() { Add(1, 2); return 0; }
int Add(int left, int right); double Add(double left, double right);int main() { Add(1, 2); Add(1.0, 2.0); return 0; }

在vs下,对上述代码进行编译链接,后编译器报错:
error LNK2019: 无法解析的外部符号 “double cdecl Add(double,double)” (?Add@@YANNN@Z) error LNK2019: 无法解析的外部符号 “int __cdecl Add(int,int)” (?Add@@YAHHH@Z)

通过上述错误可以看出,编译器实际在底层使用的不是Add名字,而是被重新修饰过的一个比较复杂的名字, 被重新修饰后的名字中包含了:函数的名字以及参数类型。这就是为什么函数重载中几个同名函数要求其参数 列表不同的原因。只要参数列表不同,编译器在编译时通过对函数名字进行重新修饰,将参数类型包含在终 的名字中,就可保证名字在底层的全局唯一性。

extern “C”

c++的函数库,c语言中并不能直接用。
有时候在C++工程中可能需要将某些函数按照C的风格来编译,在函数前加extern “C”,意思是告诉编译器,将 该函数按照C语言规则来编译

extern "C" int Add(int left, int right);int main(){    Add(1,2);  return 0;}

链接时报错:error LNK2019: 无法解析的外部符号_Add,该符号在函数 _main 中被引用
而不是c++中的报错。

引用

在之前的学习中,我们传参数的两种方式分别为,传值和传地址。

有没有什么方法能够将让传值的方式也能够起到交换的作用?
引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引 用的变量共用同一块内存空间。

使用方法

类型& 引用变量名(对象名) = 引用实体;

注意:引用类型必须和引用实体是同种类型的

引用特性

  1. 引用在定义时必须初始化
  2. 一个变量可以有多个引用
  3. 引用一旦引用一个实体,再不能引用其他实体

常引用



因为10本身是常量,修改不了


类型不同

使用场景

  1. 做参数

    void Swap(int& left, int& right)
    { int temp = left;
    left = right;
    right = temp
    }

  2. 做返回值

    int& TestRefReturn(int& a)
    { a += 10;
    return a;
    }

int& Add(int a, int b)
{    int c = a + b;    return c; }int main() {   int& ret = Add(1, 2);  Add(3, 4);  cout << "Add(1, 2) is :"<< ret <<endl;   return 0; }

注意:如果函数返回时,离开函数作用域后,其栈上空间已经还给系统,因此不能用栈上的空间作为引用类型 返回。如果以引用类型返回,返回值的生命周期必须不受函数的限制(即比函数生命周期长)。

具体参考https://blog.csdn.net/qq_40550018/article/details/81225519函数栈帧

传值、传引用效率比较

以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实 参或者返回变量的一份临时的拷贝,因此用值作为参数或者返回值类型,效率是非常低下的,尤其是当参数或者返回 值类型非常大时,效率就更低

#include <time.h> struct A {    int a[10000]; };void TestFunc1(A a) {}void TestFunc2(A& a) {}void TestRefAndValue() {  A a;// 以值作为函数参数   size_t begin1 = clock();   for (size_t i = 0; i < 10000; ++i)       TestFunc1(a);    size_t end1 = clock();// 以引用作为函数参数   size_t begin2 = clock();  for (size_t i = 0; i < 10000; ++i)   TestFunc2(a);    size_t end2 = clock();// 分别计算两个函数运行结束后的时间cout << "TestFunc1(int*)-time:" << end1 - begin1 << endl;   cout << "TestFunc2(int&)-time:" << end2 - begin2 << endl;}// 运行多次,检测值和引用在传参方面的效率区别
int main(){    for (int i = 0; i < 10; ++i)  {      TestRefAndValue();    }          return 0; }

值和引用的作为返回值类型的性能比较

#include <time.h> struct A {    int a[10000]; };A a;A TestFunc1() {    return a; }A& TestFunc2() {    return a; }void TestReturnByRefOrValue() {   // 以值作为函数的返回值类型   size_t begin1 = clock();   for (size_t i = 0; i < 100000; ++i)    TestFunc1();    size_t end1 = clock();// 以引用作为函数的返回值类型    size_t begin2 = clock(); for (size_t i = 0; i < 100000; ++i)      TestFunc2();    size_t end2 = clock();// 计算两个函数运算完成之后的时间   cout << "TestFunc1 time:" << end1 - begin1 << endl; cout << "TestFunc2 time:" << end2 - begin2 << endl; }

通过上述代码的比较,发现传值和指针在作为传参以及返回值类型上效率相差很大。

引用和指针的区别

在语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间。

int main() {int a = 10; int& ra = a;cout<<"&a = "<<&a<<endl; cout<<"&ra = "<<&ra<<endl;return 0; }

在底层实现上实际是有空间的,因为引用是按照指针方式来实现的

int main() {
int a = 10;int& ra = a;ra = 20;int* pa = &a;*pa = 20;return 0;}

我们来看下引用和指针的汇编代码对比:

引用和指针的不同点:

  1. 引用在定义时必须初始化,指针没有要求
  2. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实 体
  3. 没有NULL引用,但有NULL指针
  4. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4 个字节)
  5. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
  6. 有多级指针,但是没有多级引用
  7. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理 8. 引用比指针使用起来相对更安全

c++起始(名词修饰,extern “C” ,引用)相关推荐

  1. C++ const关键字的总结(全局/局部变量、修饰指针和引用、成员函数和数据成员、修饰类对象、const与宏定义的区别、Static与Const的区别)

    const关键字 const关键字 1.什么是const 2.使用原理 2.1.const全局/局部变量 2.2.cosnt修饰指针和引用 2.3.const修饰函数参数 2.4.const修饰函数返 ...

  2. const修饰指针和引用的用法【转贴】

    *************************************************** 更多精彩,欢迎进入:http://shop115376623.taobao.com ****** ...

  3. 吃人的那些 Java 名词:对象、引用、堆、栈

    作为一个有着 8 年 Java 编程经验的 IT 老兵,说起来很惭愧,我被 Java 当中的四五个名词一直困扰着:对象.引用.堆.栈.堆栈(栈可同堆栈,因此是四个名词,也是五个名词).每次我看到这几个 ...

  4. 【英语】语法:名词修饰名词

    现代英语的特色之一,是力求以简单的结构,表达复杂的思维.以名词作修饰语,简称"名词定语"(attributive nouns),便是朝向这目标的手段之一. 所谓名词修饰名词,就是以 ...

  5. final修饰的是引用还是引用的对象

    使用final关键字修饰一个变量时,是指引用变量不能变,引用变量所指向的对象中的内容还是可以改变的.

  6. java中final关键字,修饰变量、引用、类、方法、实例变量的问题

    一.final在英语中的意思 final在英语中表示 最终的.不可变更的. 二.final修饰的变量 局部变量: final修饰的局部变量一旦赋值就不能再次赋值,只能赋值一次.若是再次赋值会报错: 实 ...

  7. C语言中extern修饰符的用法

    在C语言中,修饰符extern用在变量或者函数的声明前,用来说明"此变量/函数是在别处定义的,要在此处引用". 0. extern修饰变量的声明.举例来说,如果文件a.c需要引用b ...

  8. C语言中的extern关键字用法

    在C语言中,修饰符extern用在变量或者函数的声明前,用来说明"此变量/函数是在别处定义的,要在此处引用". 1. extern修饰变量的声明.举例来说,如果文件a.c需要引用b ...

  9. C语言中extern的用法--转

    http://blog.sina.com.cn/s/blog_52deb9d50100ml6y.html 在C语言中,修饰符extern用在变量或者函数的声明前,用来说明"此变量/函数是在别 ...

最新文章

  1. VMware Workstation 15 Pro 永久激活密钥 下载
  2. Entity Framework Code First添加修改及删除单独实体
  3. Redis 持久化之RDB和AOF
  4. 用C# (.NET Core) 实现抽象工厂设计模式
  5. asp.net链接mysql数据库------------【个人收集】
  6. DolphinPHP
  7. Eclipse汉化教程
  8. 五分钟搞定单片机keil5 运行破解安装教程
  9. H3C nqa 配置
  10. Fragstats4.2之计算景观格局指数(一)
  11. VMware虚拟机克隆
  12. Netty学习笔记(一)--- 初识Netty
  13. 腾讯海外计费系统架构演进
  14. 了解ES6 The Dope Way第五部分:类,转译ES6代码和更多资源!
  15. 关于Hadoop在java客户端进行下载时的异常java.io.FileNotFoundException: Hadoop home directory is no existed的解决办法
  16. 苹果推iOS游戏手柄,掌上游戏主机格局变天?
  17. Django作业管理系统(1)
  18. c语言鸡兔同笼的实训报告的目的,车床实训报告实习目的
  19. [EULAR文摘] 脊柱放射学持续进展是否显著影响关节功能
  20. 顾小清:人工智能何以促进未来教育发展

热门文章

  1. HTML5 之 简单汇总
  2. 实验三 类的继承和多态性
  3. 修改窗口图标 AfxRegisterWndClass()
  4. python中print的用法_python中print用法
  5. promise将ajax变为同步,ES6-Promise改造异步请求为同步
  6. mysql count 不等于_Mysql 不同的 count 区别
  7. 关闭运动轨迹_网球初学者如何正确入门网球运动,有哪些学习细节
  8. matlabapp窗口图像_matlab – 如何自定义App Designer图形的背景?
  9. java怎么把文件写入到usb里_如何创建PowerShell脚本以将文件复制到USB闪存驱动器?...
  10. 南岸焊接机器人厂_造船三部高效焊接工艺技术年鉴