一、C和C++的区别:C和C++的主要差别,C语言缺少对bool值,引用,模板,命名空间,面向对象,异常特性的支持。C比C++更适合底层开发,因为C能够提供稳定的ABI(Application Binary Interface)接口。ABI不同于API ,API定义了源代码和库之间的接口,因此同样的代码可以在支持这个API的任何系统中编译 ,然而ABI允许编译好的目标代码在使用兼容ABI的系统中无需改动就能运行。ABI掩盖了各种细节,例如:调用约定控制着函数的参数如何传送以及如何接受返回值;系统调用的编码和一个应用如何向操作系统进行系统调用;以及在一个完整的操作系统ABI中,对象文件的二进制格式、程序库等等。
C的函数调用:
#include<stdio.h>
int add(int a,int b)
{
return a+b;
}
main()
{
int (*fun)(int )=(int (* )(int )) add;
fun f=f(20);
printf("%d\n",r);
}
该程序尽管实参和形参不匹配,但是依然能够正常运行。
下面研究函数调用的本质:
函数执行的时候有自己的临时栈
函数的参数就在临时栈中,如果函数传递实参,则用来初始化临时的参数变量,如上函数,即使传递三个参数不会报错,程序会忽略第三个参数
#include<stdio.h>
int add(int *a,int *b)
{
return (*a)+(*b);
}
main()
{
int a=20;
int b=30;
int r=add(&a,&b); \\传递指针变量,地址值
printf("%d\n",r);
int (*fun)(int )=(int (* )(int )) add;
fun f=f(20);
printf("%d\n",r);
}
二种函数结果返回方式,直接返回、通过函数的参数返回。通过参数来返回值,(告诉必须是指针)
指针指向的区域必须事先分配,在函数中操作该区域,函数返回后,该区别不会销毁
函数指定三种调用方式,__stdcall _cdecl _fastcall,这些方式直接影响编译器。
(linux中可通过gcc test.c -s与cat test.s查看对应的汇编代码)
1.决定我们函数栈压栈的顺序,函数参数从右向左压栈
2.决定函数栈清空的方式
3.决定了函数的名字转换方式
stdcall调用者清空
cdecl有专用参数来标识清空方式,统一清空
fastcall自己在返回前空间
几种类型的指针
far near huge指针
near 16
far 32位
huge 综合
二.虚拟内存
先看一个程序:
#include<stdio.h>
#include<stdlib.h>
main()
{
int *p=malloc(0);
*p=9999;
printf("%d\n",*p);
}
能够正常输出9999
一个程序程序不能访问另一个程序指向的空间,
每个程序的开始地址都是0X80084000,这个不是物理地址,是每个程序的逻辑地址,也即虚拟内存。
逻辑地址仅仅是编号,统带使用int 4字节整数表示,2的32次方,即4G的空间。每个程序提供4G的访问能力,逻辑地址与物理地址关联才有意义,这个过程称为内存映射。strace main跟踪程序执行,查以查看映射。虚拟内存的提出,目的在于不允许程序直接文章物理内存,提高程序的可靠性,有助于系统的稳定。
虚拟与物理 地址在映射的时候,有一个基本单位 4K 1000即内存页,
段错误:无效访问,访问了无法映射的物理地址。
合法访问:比如malloc分配的空间之外的空间,可以访问,但访问非法。
虚拟内存的分配
栈:编译器自动生成代码维护
堆:地址是否映射,映射的空间是否被管理
brk/sbrk 内存映射函数
帮助手册的使用,man 节 关键词
节为1-8 1:linux系统指令,shell命令
2:系统函数 查看brk/sbrk函数说明
3:标准C函数的帮助文档
7:系统的编程帮助 man 7 tcp 常用的节
分配与释放内存:
int brk(void *end) //分配空间,释放空间 与malloc 区别
1使用sbrk分配空间
2.使用sbrk得到没有映射的虚拟地址,得到一大块未分配的地址的首地址
3使用brk分配空间
4使用brk释放空间
void *sbrk(int size); //返回空间地址 如果是第一次运行,则返回没有映射的空闲空间首地址,
同时产生一个数据结构,指向该空间
sbrk与brk后台系统维护一个指针,指针默认是NULL,第一次调用sbrk,我们判定指针是否是0,是则得到大块空闲空间首地址来初始化指针
同时指针+参数size,否,则返回指针并把指针位置+size(参数)
malloc 用brk来实现
作业:写一个程序查找1-10000之间所有的素数,并且存放到缓冲,然后打印。用数组实现太耗空间,缓冲用Sbrk/brk实现。
总结:
系统操作内存有哪下几种方式:智能指针、STL、new、malloc、brk/sbrk,依次上高级到低级。
int brk(void *)
void *sbrk(int )
如果成功brk返回0 sbrk返回指针
失败 brk返回-1 sbrk返回 (void *) -1
unix函数如果错误,修改一个内部errno
打印错误方法:
1.peror 打印详细信息
2.printf("memory:%m\n"):
3.printf("::%s\n",strerror(error));
补充知识,inux中重要的函数:子符串函数 string.h cstring、内存管理函数 malloc memset mamcmp memcpy bzero、错误处理函数、标准IO函数、时间函数、类型转换函数
作业:打印1-10000之间所有孪生素数
打印当前的日期时间:格式
0000年00月00 00:00:00