C++补充(笔记)

一、sizeof

sizeof不是方法。

通过反汇编可知,,程序会在sizeof处直接给出了4字节,而不是用Call调用方法。 

二、重载原理

C无法进行重载而C++可以,是因为C++采用了name mangling/name decoration技术。因而C++默认会对符号(函数)名进行改编、修饰。

类似于如下,具体名称根据其编译器而不同。

//display_int
void display(int a) {
	cout << "display(int)-" << a << endl;
}
//display_double
void display(double a) {
	cout << "display(double)-" << a << endl;
}
//display_long
void display(long a) {
	cout << "display(long)-" << a << endl;
}

通过下面代码

 返汇编后会发现,方法的地址接不同,由此可知确实是不同方法。

三、__cplusplus

C++文件会默认在头部定义__cplusplus,表明这是C++环境

#define __cplusplus

因而可以靠着识别该宏来判断是否为C++文件

四、extern "C"

让C++中被其修饰的代码以C的标准编译进行编译,一般用于C于C++混合开发。当我们需要直接调用C写的代码时,有时并不支持C++,因而就以该方法进行。

使用方式:

//1.
extern "C" void func() {

}

//2.
extern "C" void func();

void func(){


}


//3.

extern "C"{

void func();
void func2();

}

void func(){

}
void func2(){

}

同时若如下写法,由于编译方式不同,且C++会添加修饰符,因而不会有问题。而两个都由extern "C" 则由于C不支持重载会报错。

void func();
extern "C" void func(int);
extern "C" void func();
extern "C" void func(int);

具体使用:

calc.h文件

#ifndef __CALC_H
#define __CALC_H
//这是一个C语言环境执行文件
#ifdef __cplusplus
extern "C" {
#endif
	int sum(int, int);
	int delta(int, int);
	int divide(int, int);
#ifdef __cplusplus
}

#endif
#endif

calc.c文件

#include"calc.h"
#include<stdio.h>
int sum(int pre, int pos) {
	return pre + pos;
}
int delta(int pre, int pos) {
	return pre - pos;
}
int divide(int pre, int pos) {
	if (pos == 0) {
		printf("除数不可以为零!!\n");
		return 0;
	}
	return pre / pos;
}

主程序

#include<iostream>
#include"calc.h"
using namespace std;


int main() {
	cout<<sum(3,4)<<endl;
	cout << divide(5, 0) << endl;
	return 0;
}

五、避免多次编译

#pragma once有的编译器支持,有的编译器不支持。同时它是针对整个文件的。

#ifndef,#define,#endif则是C++语言的编译器上都是有效的。同时它可以针对任意部分。

六、内联函数

 将函数调用直接展开为函数体代码,增大代码体积。如下图:

#include<iostream>
using namespace std;
//看上去
inline int sum(int,int);
int main() {
	int a =  sum(3, 2);
	cout << a << endl;
	return 0;
}
inline int sum(int v1,int v2) {
	return v1 + v2;

}


//实际上
int main() {
    int a = 3 + 2 ;
	cout << a << endl;
	return 0;
}

当函数代码体积不是很大,频繁调用次数不是太多时,可以使用内联函数以减少对于栈空间的开辟以及回收栈空间操作。

有时即使为内联函数,也不会成为内联,取决于编译器。比如递归就不会成为内联函数。

通过调试状态,进行反汇编会发现两者代码一致,是由于内联属于优化,在release时才会变化。同时在release模式,编译器也会做一定优化,使得代码更优,因此可能看不出区别,可以在下图禁止掉其优化以及内联函数扩展部分进行修改。(不同编译器不同)

非内联

 内联

七、内联函数与宏

 宏替换也可以像内联函数一样,减少调用。

#include<iostream>
#define add(v1,v2) v1+v2
using namespace std;

int main() {
	int a = add(3,2);
	cout << a << endl;
	return 0;
}

但是内联函数多了语法检测与函数特性。当宏写错时,只会在使用部分报错同时不会有传参的提示。

同时有一个问题如下图:

原本希望:

实际上通过:

 此处变为了 c = (++a) + (++a)

八、引用

相当于变量的别名,在初始化后不可以再改变指向。不可以为空。

可以用一个引用初始化另一个引用,相当于一个变量有多个别名。

没有“引用的引用”用法或“指向引用的指针”,因为无意义。

#include<iostream>
using namespace std;

int main() {
	int a = 10;
	int b = 30;
	int &c = a;
	c = 20;
	cout << a << endl;
	c = b;
	b++;
	cout << c << endl;
	cout << a << endl;
	int& d = c;
	cout << d << endl;
	d++;
	cout << c << endl;
	cout << a << endl;

    int f[] = { 1,2 };
	int&array = f[1];
	int(&array2)[2] = f
	cout << array << endl;	//引用了数组中数据
	cout << *array2 << endl;	//引用了存储了数组首地址的变量
	return 0;
}

引用较指针而言,更安全,使用更简单。

如下图使用时:

指针:

引用:

引用的本质 

引用的本质就是指针,不过是编译器弱化了功能或加强了对其限制的指针。因而在复制构造函数时,仅能使用引用而不是指针。(此外,复制构造函数不能为值的原因即为在传参是会生成无名对象传递,此时又一次对无名对象进行复值构造,导致套娃。又为了避免该问题又为了保证对原对象不修改,用了const。)

通过反汇编(将符号名去掉):

可以发现引用和指针复制以及修改变量值时,其机器码以及汇编指令均一样(不一样的为相对地址)。因而认为引用本质为指针。

const修饰引用

 可以将引用理解为 int *const p 的写法,将&与*const等价,由此可以理解一下代码不报错原因。

#include<iostream>
using namespace std;

int main() {
	int a = 3;
	int& const b = a;
	b = 4;
	//不报错
	int c = 3;
	int const&  d = a;
	d = 4;
	//报错
	return 0;
}

const 引用,即常引用,可以引用临时数据或表达式。

#include<iostream>
using namespace std;
int func();
int main() {
	int a = 1;
	int b = 2;
	const int& ref = 30;
	const int& exp = a + b;
	const int& fun = func();
	return 0;
}

使用如下,当我们需要参数为引用的同时兼容传递常量时,改写法十分有效。

#include<iostream>
using namespace std;
int add(const int &pre,const int &post);
int main() {
	int a = 3;
	int b = 4;
	add(a, b);
	add(1, 2);
	return 0;
}

int add(const int& pre, const int& post) {
	return pre + post;
}

注意下图的问题:

#include<iostream>
using namespace std;

int main() {
	int a = 10;
	const int& age = a;
	const long& rage = a;
	a = 2;
	cout << age <<endl;
	cout << rage << endl;
	return 0;
}

通过反汇编可知:

对于const long&,程序将a的值移动到了一个无名对象(额外的地址)之中,然后让rage指向。因此a改变而rage不变化。

九、内联汇编

向C++中嵌套汇编语言,全局变量使用时可以写地址,局部变量因地址可能会变化而必须以相对地址表示。

可以模仿VisualStudio的反汇编中的伪代码写指令。

#include<iostream>
using namespace std;

int main() {
	int a = 10;
	__asm {
		mov eax, [a]
		add eax, 3
		mov [a], eax
	}
	cout << a << endl;
	return 0;
}

汇编语言编写可提高代码的执行效率,同时有些操作无法通过高级语言实现,或者实现起来很困难时,可以通过汇编语言从底层操作。

不同的CPU编译而成的机器码都是不同的,因而通过自己写汇编更准确的到达目的。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值