用django怎么做网站,网站备案 内容,怎么用织梦做自己的网站,wordpress去掉wordpress.org名字修饰(name Mangling)
在C/C中#xff0c;一个程序要运行起来#xff0c;需要经历以下几个阶段#xff1a;预处理、编译、汇编、链接。
Name Mangling是一种在编译过程中#xff0c;将函数、变量的名称重新改编的机制#xff0c;简单来说就是编译器为了区分各 个函数…名字修饰(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)” (?AddYANNNZ) error LNK2019: 无法解析的外部符号 “int __cdecl Add(int,int)” (?AddYAHHHZ)
通过上述错误可以看出编译器实际在底层使用的不是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中的报错。
引用
在之前的学习中我们传参数的两种方式分别为传值和传地址。 有没有什么方法能够将让传值的方式也能够起到交换的作用 引用不是新定义一个变量而是给已存在变量取了一个别名编译器不会为引用变量开辟内存空间它和它引 用的变量共用同一块内存空间。
使用方法
类型 引用变量名(对象名) 引用实体 注意引用类型必须和引用实体是同种类型的
引用特性
引用在定义时必须初始化一个变量可以有多个引用引用一旦引用一个实体再不能引用其他实体 常引用 因为10本身是常量修改不了 类型不同
使用场景 做参数 void Swap(int left, int right) { int temp left; left right; right temp } 做返回值 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;couta aendl; coutra raendl;return 0; }在底层实现上实际是有空间的因为引用是按照指针方式来实现的
int main() {
int a 10;int ra a;ra 20;int* pa a;*pa 20;return 0;}我们来看下引用和指针的汇编代码对比 引用和指针的不同点:
引用在定义时必须初始化指针没有要求引用在初始化时引用一个实体后就不能再引用其他实体而指针可以在任何时候指向任何一个同类型实 体没有NULL引用但有NULL指针在sizeof中含义不同引用结果为引用类型的大小但指针始终是地址空间所占字节个数(32位平台下占4 个字节)引用自加即引用的实体增加1指针自加即指针向后偏移一个类型的大小有多级指针但是没有多级引用访问实体方式不同指针需要显式解引用引用编译器自己处理 8. 引用比指针使用起来相对更安全