补码的非
一个补码x的加法逆元即为补码的非。
加法逆元+x =0,通常为 补码 x 真值 的相反数的补码,记为 -x(最小数除外,为自身)。
用处:一个负数 的 补码的非为 该负数相反数的补码,且正数补码等于原码,可以快速算出真值,真值取反即为最初的负数。所以可以根据补码的非快速算出一个负数补码的真值。
方法:
例子:补码0xfffffffa的真值为多少?
找到0xfffffffa最右边的1,将其左边所有位取反得到:0x00000006,该补码非真值为6,所以0xfffffffa真值为-6.
数组越界
原因:对越界的数组元素的写操作会破坏存储在栈中的状态信息(比如返回地址),当程序使用被破坏的状态,试图重新加载寄存器或执行ret指令时,就会出现很严重的错误。
一种常见的状态破坏称为缓冲区溢出(buffer overflow),字符串数组的长度超过了为数组分配的空间。可能遭受缓冲区溢出攻击。
对抗策略:1.栈随机化;2.栈破坏检测,存储特殊的金丝雀值(哨兵值);3限制可执行代码区域。
程序优化的方法
gcc自动优化:
1.一个文件内内联函数替换优化函数调用。
2.循环展开(n次循环 缩小为n/k 次)
用优化等级3及以上调用GCC,可自动执行循环展开
3.重新结合变换
在满足结合律(或者基本满足)的情况下,更改结合顺序,使不依赖上下文的数据先结合在一起。可靠性不如循环展开和多个累积变量。
需要手动进行的优化:
1.消除循环的低效率
代码移动:识别要执行多次(例如在循环里)但是计算结果不会改变的计算,移到循环前面。
2.减少过程调用
3.消除不必要的内存引用
因为指针很少被编译器优化,所以应该尽量少用指针,数组也相当于指针引用。
很多时候可以可以先用局部变量充当中介,因为局部变量存放在寄存器中,循环结束,再放进数组(指针引用)中。
例子:
读写数组元素要读写内存,先用局部变量来代替数组元素效率更高,因为局部变量存储在寄存器中。
//效率高
vector<int> singleNumber(vector<int>& nums) {
int XORsum=0,classify=0;
for(int num:nums)
XORsum^=num;
classify=XORsum&(-XORsum);
int a=0,b=0;
for(int num:nums){
if(classify&num)
a^=num;
else
b^=num;
}
return {a,b};
//效率低
vector<int> singleNumber(vector<int>& nums) {
vector<int> res{0,0};
int XORsum=0,classify=0;
for(int num:nums)
XORsum^=num;
classify=XORsum&(-XORsum);
for(int num:nums){
if(classify&num)
res[0]^=num;
else
res[1]^=num;
}
return res;
}
3.多个累积变量
在满足结合律(或者基本满足)的情况下,将一个循环运算分成两个并行,最后再结合。
4.使用AVX向量指令,多路并行向量运算。
5.对于条件判断语句,使用“功能性的”风格书写,使其产生条件数据传送而不是条件控制转移。
“功能性”风格:用条件操作来计算值,然后用这些值来更新程序状态。
对立于“命令式”风格:用条件语句来有选择的更新程序状态。
但不是所有条件行为都能用条件数据传送来完成,有时候无法避免用条件控制转移。
P380
6.程序剖析
使用程序剖析工具
SSE、AVX
进程
定义:进程的经典定义就是一个执行中程序的实例。系统中的每个程序都运行在某个进程的上下文(context)中。上下文是由程序正确运行所需的状态组成的。这个状态包括存放在内存中的程序的代码和数据,它的栈、通用目的寄存器的内容、程序计数器、环境变量以及打开文件描述符的集合。
内存地址分析:https://blog.csdn.net/qq_40586164/article/details/107550072
线程:
有些进程同时干不止一件事,比如Word,它可以同时进行打字、拼写检查、打印等事情。在一个进程内部,要同时干多件事,就需要同时运行多个“子任务”,我们把进程内的这些“子任务”称为线程。线程是最小的执行单元。
(1)线程就是运行在进程的上下文中的逻辑流(是在进程中活动的对象),线程由内核自动调度。
(2)线程都有自己的线程上下文,包括线程ID,线程栈,栈指针,程序计数器,通用目的寄存器,条件码。
(3)所有运行在一个进程的线程都共有虚拟地址空间。
虚拟内存
https://www.jianshu.com/p/a7633d7687c2
虚拟内存是计算机系统内存管理的一种技术。
缓存:它使得应用程序认为它拥有连续的可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。
内存管理:操作系统为每个进程提供了独立的虚拟地址空间,可以有效的管理内存。
内存保护:虚拟内存可以控制进程对内存系统的访问,比如PTE的许可位可以控制对一个虚拟页面内容的访问,如修改只读内容会触发段异常。
目前,大多数操作系统都使用了虚拟内存,如Windows家族的“虚拟内存”;Linux的“交换空间”等。
地址翻译