一、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编译而成的机器码都是不同的,因而通过自己写汇编更准确的到达目的。