1、makefile的作用是什么?
makefile定义了一系列的规则来指定哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为 makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。makefile带来的好处就是--“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。
makefile文件保存了编译器和连接器的参数选项,还表述了所有源文件之间的关系(源代码文件需要的特定的包含文件,可执行文件要求包含的目标文件模块及库等)。创建程序(make程序)首先读取makefile文件,然后再激活编译器,汇编器,资源编译器和连接器以便产生最后的输出,最后输出并生成的通常是可执行文件.创建程序利用内置的推理规则来激活编译器,以便通过对特定CPP文件的编译来产生特定的OBJ文件.
Tip:在Makefile中的命令,必须要以[Tab]键开始
2、 数据库与文件进行数据存储有哪些区别?
(1)文件系统用文件将数据长期保存在外存上,数据库系统用数据库统一存储数据。
(2)文件系统中的程序和数据有一定的联系,数据库系统中的程序和数据分离。
(3)文件系统用操作系统中的存取方法对数据进行管理,数据库系统用DBMS统一管理和控制数据。
(4)文件系统实现以文件为单位的数据共享,数据库系统实现以记录和字段为单位的数据共享。
3、系统调用与库函数的区别
(1)库函数是语言或应用程序的一部分,而系统调用是内核提供给应用程序的接口,属于系统的一部分
(2)库函数在用户地址空间执行,系统调用是在内核地址空间执行,库函数运行时间属于用户时间,系统调用属于系统时间,库函数开销较小,系统调用开销较大
(3)库函数是有缓冲的,系统调用是无缓冲的
(4)系统调用依赖于平台,库函数并不依赖
函数库调用 | 系统调用 |
平台移植性好 | 依赖于内核,不保证移植性 |
调用函数库中的一段程序(或函数) | 调用系统内核的服务 |
一个普通功能函数的调用 | 是操作系统的一个入口点 |
在用户空间执行 | 在内核空间执行 |
它的运行时间属于“用户时间” | 它的运行时间属于“系统”时间 |
属于过程调用,调用开销较小 | 在用户空间和内核上下文环境间切换,开销较大 |
库函数数量较多 | UNIX中大约有90个系统调用,较少 |
典型的C函数库调用:printf scanf malloc | 典型的系统调用:fork open write |
4、为什么选择系统调用?什么时候使用系统调用操作文件?
(1)why
使用系统调用是因为系统资源的有限性以及内核管理的方便,系统调用将上层内的应用开发与底层的硬件实现分开,上层应用不需要关注底层硬件的具体实现。Linux的系统调用使用软中断实现,使用系统调用后,该程序的状态将从用户态切换到内核态。库函数实现最终也要调用系统调用函数,但它封装了系统调用操作,从而增加了代码的可移植性。
(2)when
每一个运转的程序——也叫进程——都会拥有一些相关联的文件描述符(file descriptor)。这是些不大的整数,可以用来使用打开了的文件或者设备。有多少个文件描述符可以使用,取决于系统如何配置。
文件操作系统调用
1)创建
int creat(const char *filename,mode_t mode);
2)打开
int open(const char *filename,int flags);
如果flags使用了O_CREATE标志则使用
int open(const char *filename,int flags,mode_t mode);
3)读写
int read(int fd,const void *buf,size_t length);
int write(int fd,const void *buf,size_t length);
4)定位
int lseek(int fd,offset_t offset,int whence);
whence可为一下值:
SEEK_SET:相对文件开头
SEEK_CUR:相对于文件读写指针的当前位置
SEEK_END:相对于文件末尾
5)关闭
int close(int fd);
5、为什么选择库函数?什么时候使用库函数操作文件?
(1)利用库函数操作文件具有跨平台的作用;
库函数对文件的操作实际上是通过系统调用来实现的。例如 C库函数 fwrite() 就是通过 write() 系统调用来实现的。
但是使用库函数也有系统调用的开销,为什么不直接使用系统调用呢?
这是因为,读写文件通常是大量的数据(这种大量是相对于底层驱动的系统调用所实现的数据操作单位而言)。这时,使用库函数就可以大大减少系统调用的次数。这一结果又源于缓冲区技术,在用户空间和内核空间对文件操作都使用了缓冲区。
例如:用 fwrite() 写文件,都是先将内容写到用户空间缓冲区,当用户空间缓冲区满或者写结束时才将内核缓冲区内容写到文件对应的硬件媒介。
(2)操作
***库函数 - 读文件
size_t fread(void *ptr, size_t size, size_t n, FILE *stream)
功能:从stream指向的文件中读取n个字段,每个字段为size字节,并将读取的数据放入ptr所指向的字符数组中,返回实际已读取的字节数。(读出来的数据量为size*n)
***库函数 - 写文件
size_t fwrite(const void *ptr, size_t size, size_t n, FILE *stream)
功能:从缓冲区ptr所指向的数组中把n个字段写到stream指向的文件中,每个字段长为size个字节,返回实际写入的字段数。
***库函数 - 创建和打开
FILE *fopen(const char *filename, const char *mode)
filename:打开的文件名(包含路径,缺省为当前路径)
mode:打开模式
6、为什么数据库选择sqlite?还有那些嵌入式数据库?特点是什么?
(1)SQLITE功能简约,小型化,追求最大磁盘效率;只是单机上用的,数据量不是很大,需要方便移植或者需要频繁读/写磁盘文件的话,就用SQLite比较合适.
(2) 嵌入式数据库及其特点
**************************SQLite**************************
SQLite诞生于2000年5月,这几年增长势头迅猛无比,目前版本是3.3.8。
SQLite的特点如下:
1、无需安装配置,应用程序只需携带一个动态链接库。
2、非常小巧,For Windows 3.3.8版本的DLL文件才374KB。
3、ACID事务支持,ACID即原子性、一致性、隔离性、和持久性(Atomic、Consistent、Isolated、和 Durable)。
4、数据库文件可以在不同字节顺序的机器间自由的共享,比如可以直接从Windows移植到Linux或MAC。
5、支持数据库大小至2TB。
**************************Berkeley DB**************************
主页:http://www.oracle.com/database/berkeley-db/index.html
Berkeley DB是由美国Sleepycat Software公司开发的一套开放源码的嵌入式数据库的程序库,它于1991年发布,号称“为应用程序开发者提供工业级强度的数据库服务”,可谓是老牌悍将。Sleepycat现已被甲骨文(ORACLE)公司收购。
Berkeley DB的特点如下:
1、嵌入式,无需安装配置。
2、为多种编程语言提供了API接口,其中包括C、C++、Java、Perl、Tcl、Python和PHP等等。
3、轻便灵活。它可以运行于几乎所有的UNIX和Linux系统及其变种系统、Windows操作系统以及多种嵌入式实时操作系统之下。
4、可伸缩。它的Database library才几百KB大小,但它能够管理规模高达256TB的数据库。它支持高并发度,成千上万个用户可同时操纵同一个数据库。
**************************Firebird嵌入服务器版(Embedded Server)**************************
从Interbase开源衍生出的Firebird,充满了勃勃生机。虽然它的体积比前辈Interbase缩小了几十倍,但功能并无阉割。为了体现Firebird短小精悍的特色,开发小组在增加了超级服务器版本之后,又增加了嵌入版本,最新版本为2.0。
Firebird的嵌入版有如下特色:
1、数据库文件与Firebird网络版本完全兼容,差别仅在于连接方式不同,可以实现零成本迁移。
2、数据库文件仅受操作系统的限制,且支持将一个数据库分割成不同文件,突破了操作系统最大文件的限制,提高了IO吞吐量。
3、完全支持SQL92标准,支持大部分SQL-99标准功能。
4、丰富的开发工具支持,绝大部分基于Interbase的组件,可以直接使用于Firebird。
5、支持事务、存储过程、触发器等关系数据库的所有特性。
6、可自己编写扩展函数(UDF)。