linux系统调用和库函数调用的区别.doc
- 格式:doc
- 大小:30.00 KB
- 文档页数:4
XX年嵌入式系统开发工程师考试试题及答案国内普遍认同的嵌入式系统定义为:以应用为中心,以计算机技术为根底,软硬件可裁剪,适应应用系统对功能、可靠性、本钱、体积、功耗等严格要求的专用计算机系统。
下面是的关于嵌入式系统开发工程师考试试题及答案,希望大家认真阅读!1、用预处理指令#define声明一个常数,用以说明一年中有多少秒(忽略闰年问题);写一个“标准”宏MIN函数,这个宏输入两个参数并返回较小的一个。
2、用变量a给出下面的定义:(1)一个整型数(An integer);(2)一个指向整型数的指针(A pointer to an integer);(3)一个指向指针的指针,它指向的指针是指向一个整型数(A pointer to a pointer to an integer);(4)一个有10个整型数的数组(An array of 10 integers);(5)一个有10个指针的数组,该指针是指向一个整型数的(A array of 10 pointers to integers);(6)一个指向有10个整型数组的指针(A pointer to an array of 10 integers);(7)一个指向函数的指针,该函数有一个整型参数并返回一个整型数(A pointer to a function that takes an integer as an argument returns an integer);(8)一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数(An array of 10 pointers to functions that take an integer argument and return an integer);3、关键字volatile有什么含义?并举出三个不同的例子。
4、嵌入式系统总是要用户对变量或存放器进展位操作,给定一个整型变量a,写两段代码,第一个设置a 的bit 3,第二个去除a 的bit 3,在以上操作中,要保持其他位不变。
qt默认的编程语言为C++语言。
如果你用qt编译.c文件,会出现找不到C语言的默认头文件等错误(如:stdio.h等)。
qt中不支持extern "C"{}的这种写法,我前几天有一个C程序需要移植到Qt的工程中,本希望直接extern "C"就ok了,但发现qt4居然不支持这种写法。
我的程序中用到了好几个linux系统头文件,是向串口发指令之类的程序,程序中用到了互斥锁并创建了一个线程。
如果再用qt语言来写一遍的话我会挂掉的,所以没有办法,在网上找了半天,终于找到解决方法。
将.c文件编译为函数库的方式在qt下调用,这种方法貌似行得通,我就开始行动了。
下面的内容讲得比较多,比较全,比较适合初学者,是我在网上down的,给出了原网站的链接,最后给出了一个程序。
经过自己整理好归纳如下:需要说明的是:使用gcc可以将程序编译成动态库或者静态库的形式,它们在程序中的调用的方式也不尽相同,给出的程序中调用的是动态连接库。
编译成动态的还是静态的根据自己的需要进行。
如果原C程序编译的时候需要gcc的额外选项(如gcc -lpthread -o hello hello.c)等,建议采用动态的形式。
1.什么是静态连接库,什么是动态链接库静态链接库与动态链接库都是共享代码的方式,如果采用静态链接库,则无论你愿不愿意,lib 中的指令都全部被直接包含在最终生成的EXE 文件中了。
但是若使用DLL,该DLL 不必被包含在最终EXE 文件中,EXE 文件执行时可以“动态”地引用和卸载这个与EXE 独立的DLL 文件。
静态链接库和动态链接库的另外一个区别在于静态链接库中不能再包含其他的动态链接库或者静态库,而在动态链接库中还可以再包含其他的动态或静态链接库。
在windows和linux上都是相同的,只不过文件的格式不同而已。
/winston/archive/2008/07/05/1236273.html2.gcc生成静态库和动态库第1步:编辑得到举例的程序--hello.h、hello.c和main.c;第2步:将hello.c编译成.o文件;无论静态库,还是动态库,都是由.o文件创建的。
linux操作系统下fork函数理解在Linux操作系统中,fork函数是一个非常重要的系统调用,它用于创建一个新的进程。
本文将详细解释fork函数的作用、用法和实现原理,并介绍如何利用fork函数实现进程间通信以及避免一些常见的问题。
一、fork函数的作用和用法在Linux系统中,fork函数用于创建一个新的进程,该进程是调用fork函数的进程的一个副本。
具体而言,fork函数会创建一个新的进程,称为子进程,而调用fork函数的进程被称为父进程。
子进程从fork函数返回的地方开始执行,而父进程则继续执行fork函数之后的代码。
简单来说,fork函数的作用就是将一个进程复制成两个几乎完全相同的进程,但它们具有不同的进程ID(PID)。
fork函数的用法非常简单,只需要在程序中调用fork()即可。
具体代码如下所示:```c#include <stdio.h>#include <sys/types.h>#include <unistd.h>int main() {pid_t pid = fork();if (pid == 0) {// 子进程代码} else if (pid > 0) {// 父进程代码} else {// fork失败的处理代码}return 0;}```在上述代码中,首先使用pid_t类型的变量pid存储fork函数的返回值。
如果pid等于0,则表示当前执行的是子进程的代码;如果pid大于0,则表示当前执行的是父进程的代码;如果pid小于0,则表示fork函数调用失败。
二、fork函数的实现原理在Linux系统中,fork函数的实现是通过复制父进程的内存空间来创建子进程的。
具体来说,fork函数会创建一个新的进程控制块(PCB),并将父进程的PCB全部复制到子进程的PCB中,包括代码段、数据段、堆栈等。
由于子进程是父进程的一个副本,所以它们的代码和数据是完全相同的。
2022年河南工业大学计算机科学与技术专业《操作系统》科目期末试卷B(有答案)一、选择题1、在系统内存中设置磁盘缓冲区的主要11的是()。
A.减少磁盘1/0次数,B.减少平均寻道时间C.提高磁盘数据可靠性D.实现设备无关性2、下列选项中,磁盘逻辑格式化程序所做的T作是()I.对磁盘进行分区II.建立文件系统的根目录III.确定磁盘扇区校验码所占位数IV.对保存空闲磁盘块信息的数据结构进行初始化,A. 仅IIB.仅II、IVC.仅III,IVD.仅I、II、IV3、在操作系统中,一方面每个进程具有独立性,另一方面进程之间具有相互制约性。
对于任何两个并发进程,它们()。
A.必定无关B.必定相关C.可能相关D.可能相同4、对进程的管理和控制使用()。
A.指令B.原语C.信号量D.信箱通信5、()有利于CPU繁忙型的作业,而不利于1/0繁忙型的作业(进程)。
A.时间片轮转调度算法B.先来先服务调度算法C.短作业(进程)优先调度算法D.优先权调度算法6、解决主存碎片问题较好的存储器管理方式是()A.可变分区B.分页管理C.分段管理D.单一连续分配7、在空白表中,空白区按其长度由小到大进行查找的算法称为()算法。
A.最佳适应B.最差适应C.最先适应D.先进先出8、假设5个进程P0、P1、P2、P3、P4共享3类资源R1、R2、R3.这些资源总数分别为18、6、22。
T0时刻的资源分配情况(见表),此时存在的一个安全序列是()。
A. P0, P2, P4, P1, P3B. P1, P0, P3, P4, P2C. P2, P1, P0, P3, P4D. P3, P4, P2, P1, P09、下面叙述中,错误的是()A.操作系统既能进行多任务处理,又能进行多重处理B.多重处理是多任务处理的子集,C.多任务是指同一时间内在同一系统中同时运行多个进程D.一个CPU的计算机上也可以进行多重处理10、I/O交通管制程序的主要功能是管理()的状态信息。
网上搜索到一些博客有对这两个函数的解释,看了之后还是犯迷糊。
exit()函数定义在stdlib.h头文件中,_exit()定义在unistd.h头文件中,这是区别之一。
调用_exit()函数时,其会关闭调用进程的所有文件描述符,清理内存和内核数据,但不会刷新流(stdin, stdout, stderr ...)。
exit()函数是在_exit()函数之上的一个封装,其会调用_exit(),并在调用之前先刷新流,并且exit()系统调用之前要检查文件的打开情况,把文件缓冲区的内容写回文件。
所以要保证数据的完整性,得调用exit()函数。
但是也查到一些解释,《Linux环境C程序设计》(第二版 徐诚等编著)一书第205页exit系统调用小节中有这样描述:“由fork()函数创建的子进程分支里,正常情况下使用函数exit()是不正确的,这是因为使用它会导致标准输入输出的缓冲区被清空两次,而且临时文件可能被意外删除。
”这与上面的解释相悖了,究竟谁是对的?基于上面的描述,我还有以下疑问:1、刷新缓冲区是简单的删除其中的数据,还是要进行一些操作,例如保存数据再清空?2、exit()为什么会导致标准输入输出的缓冲区被清空两次?希望有高手不吝赐教,解释exit()和_exit()的区别及使用方法。
谢谢!添加评论 分享匿名用户知乎用户、知乎用户、知乎用户 等人赞同基本来说,_Exit(或 _exit,建议使用大写版本)是为 fork 之后的子进程准备的特殊 API。
功能见 [1],讨论见 [2]。
因为在 fork 之后,exec 之前,很多资源还是共享的(如某些文件描述符),如果使用 exit 会关闭这些资源,导致某些非预期的副作用(如删除临时文件等)。
「刷新」是对应 flush,意思是把内容从内存缓存写出到文件里,而不仅仅是清空(所以常见的对 stdin 调用 flush 的方法是耍流氓而已)。
如果在 fork 的时候父进程内存有缓冲内容,则这个缓冲会带到子进程,并且两个进程会分别 flush (写出)一次,造成数据重复。
libc syscall 函数libc中的syscall函数是一个C库函数,在Linux系统中用来进行系统调用。
它是一个非常底层的函数,需要使用机器语言进行编写。
然而,大多数开发者不需要直接操作syscall函数,因为这个函数已经封装为较为高层次的接口,如read、write和open等。
syscall函数可以完成各种系统调用,并且几乎支持所有的系统调用。
在Linux中,系统调用是通过中断(interrupt)指令执行的,由内核处理。
syscall函数的原型如下:long syscall(long number, ...)其中,number是系统调用号,内核将根据这个号码来执行相关的系统调用。
其它参数是特定系统调用所需要的参数,参数个数和类型根据具体系统调用而定。
返回值为系统调用的结果。
对于syscall函数的调用,可以按以下的方式完成:```C#include <sys/syscall.h>long result = syscall(SYS_mysyscall, myparam1, myparam2, ...);```上述的示例代码中,第一个参数是定义了该系统调用的宏(这里为"SUS_mysyscall"),之后是需要用到的参数。
系统调用号的宏定义在 /usr/include/asm/unistd.h 文件中,通常以SYS_开头。
该头文件是内核的接口之一,可以看到系统调用和相应的参数。
如果需要调用一个函数,可以在这个头文件中查找对应的宏,并确定所需的参数。
例如,下面是sys_exit的定义:```#define __NR_exit 1__SYSCALL(__NR_exit,sys_exit)```其中,__NR_exit是sys_exit的系统调用号。
__SYSCALL宏被定义在内参考手册中,它将__NR_exit作为参数,然后定义sys_exit的声明。
```Casmlinkage long sys_exit(int error_code);```在上面的声明中,asmlinkage关键字指示编码器:这是一个绝对不能被优化的方法,所有的参数都必须通过堆栈传递。
Linux系统调⽤fsync函数详解功能描述:同步内存中所有已修改的⽂件数据到储存设备。
⽤法:#include <unistd.h>int fsync(int fd);参数:fd:⽂件描述词。
返回说明:成功执⾏时,返回0。
失败返回-1,errno被设为以下的某个值EBADF:⽂件描述词⽆效EIO :读写的过程中发⽣错误EROFS, EINVAL:⽂件所在的⽂件系统不⽀持同步强制把系统缓存写⼊⽂件sync和fsync函数,, fflush和fsync的联系和区别2010-05-10 11:25传统的U N I X实现在内核中设有缓冲存储器,⼤多数磁盘I / O都通过缓存进⾏。
当将数据写到⽂件上时,通常该数据先由内核复制到缓存中,如果该缓存尚未写满,则并不将其排⼊输出队列,⽽是等待其写满或者当内核需要重⽤该缓存以便存放其他磁盘块数据时,再将该缓存排⼊输出队列,然后待其到达队⾸时,才进⾏实际的I / O操作。
这种输出⽅式被称之为延迟写(delayed write)(Bach 〔1 9 8 6〕第3章详细讨论了延迟写)。
延迟写减少了磁盘读写次数,但是第4章⽂件和⽬录8 7下载却降低了⽂件内容的更新速度,使得欲写到⽂件中的数据在⼀段时间内并没有写到磁盘上。
当系统发⽣故障时,这种延迟可能造成⽂件更新内容的丢失。
为了保证磁盘上实际⽂件系统与缓存中内容的⼀致性,U N I X系统提供了s y n c和f s y n c两个系统调⽤函数。
#include <unistd.h>void sync(void);int fsync(intf i l e d e s) ;返回:若成功则为0,若出错则为-1s y n c只是将所有修改过的块的缓存排⼊写队列,然后就返回,它并不等待实际I / O操作结束。
系统精灵进程(通常称为u p d a t e )⼀般每隔3 0秒调⽤⼀次s y n c函数。
这就保证了定期刷新内核的块缓存。
一、ANSI C/C++方面的知识一.1、简答题。
下面的题目必须全部答对才给分(20分):1、如何在C中初始化一个字符数组。
2、如何在C中为一个数组分配空间。
3、如何初始化一个指针数组。
4、如何定义一个有10个元素的整数型指针数组。
5、s[10]的另外一种表达方式是什么。
6、GCC3.2.2版本中支持哪几种编程语言。
7、要使用CHAR_BIT需要包含哪个头文件。
8、对(-1.2345)取整是多少?9、如何让局部变量具有全局生命期。
10、C中的常量字符串应在何时定义?11、如何在两个.c文件中引用对方的变量。
12、使用malloc之前需要做什么准备工作。
13、realloc函数在使用上要注意什么问题。
14、strtok函数在使用上要注意什么问题。
15、gets函数在使用上要注意什么问题。
16、C语言的词法分析在长度规则方面采用的是什么策略?17、a+++++b所表示的是什么意思?有什么问题?18、如何定义Bool变量的TRUE和FALSE的值。
19、C语言的const的含义是什么。
在定义常量时,为什么推荐使用const,而不是#define。
20、C语言的volatile的含义是什么。
使用时会对编译器有什么暗示。
一.2、问答题。
1、———————————————————–―匈牙利命名法‖有什么优缺点?(2分)2、———————————————————–下面x, y, *p的值是多少,有什么问题?(2分)int x, y, z = 2;int *p=&z;x=sizeof*p;y=x/*p; /* x=?, *p=?, y=?, 有什么问题?*/ 3、———————————————————–下面的语句是什么意思?如何声明或定义才使它们更易懂?(10分) int (*foo())();int (*foo())[];int (*foo[])();(*(void(*)())0)();void (*signal(int,void(*)(int)))(int); 4、———————————————————–本题(2分)。
刚毕业的时候,做了将近一年的Window下的程序开发,主要用MFC,那是也不明白程序在操作系统角度从上到下的整个调用层次。
遇到调用库函数,不明白,就查MSDN,每个月1500行代码左右,那是以为这就是软件开发了。
后来跳槽的另外一家公司,工作也是Windows下的程序开发,这里可以用到多线程、COM组件,还能用到涉及模式,那是高兴的不得了。
刚开始用到多线程,就买了一本书《WIN32多线程程序设计》,边学边用。
创建线程有好几种方法,比如:CreatThread 和_beginthread()等,记得当时不明白这几种方法有何区别,就随便拿一个用。
心中有疑问:怎么创建一个线程这么多函数?WINAPI、CRT、MFC 到底有何关联?最近读《程序员的自我修养》一书,给了我明确的答复。
参考下图:创建线程函数分属不同的层次/类库,如下:1.WINAPI:CreateThread();2.CRT: _beginthread(); 和_beginthreadex();3.MFC AfxBeginThread();从上图可以看到,CRT和MFC函数最终都是调用WINAPI来实现的。
即CRT和MFC库函数都是对WIN API的封装。
Linux下应用程序调用层次如下图:上图只是列出了CRT,当然也存在其它很多类库,比如Linux下的线程库QT,也是对系统调用的封装。
从Windows和linux程序调用层次图,我们可以看到有如下区别:Linux下可以直接进行程序调用,而Windows下不能直接进行系统调用。
即Windows下的系统调用接口微软并没有开放给developer, 而是在系统调用上面添加了一层WINAPI。
至于微软为什么不开放系统调用,而添加一层WINAPI,诸位可以参考《程序员的自我修养》第12章的12.3.2。
Windows API是以DLL 导出函数的形式暴露给developer的,核心DLL有kernel32.dll、user32.dll和gdi32.dll. 我们可以用dumpbin /EXPORTS *.dll命令来查看每个dll的导出函数。
linux 下的gettickcount函数Linux是一种流行的操作系统,被广泛应用于各种设备和领域。
在Linux系统中,有许多与时间相关的函数可以用来测量程序的执行时间和性能。
其中一个常用的函数是"gettickcount"。
本篇文章将介绍Linux下的"gettickcount"函数的用途、用法以及与其他类似函数的区别。
"gettickcount"函数是一种用于获取系统时钟滴答数的函数。
它返回一个无符号整数,表示自系统启动以来经过的毫秒数。
这个数值在系统启动后会一直递增,直到溢出为止。
"gettickcount"函数的返回值可以用来测量程序的运行时间、延迟和性能。
在Linux系统中,"gettickcount"函数实际上是通过读取系统的时钟频率和计数器值来计算毫秒数的。
这是由于在Linux中,时钟频率和计数器值的单位不一定是毫秒级别的。
因此,"gettickcount"函数实际上是一个通过转换和计算来实现的辅助函数。
使用"gettickcount"函数非常简单。
只需在程序中包含头文件,并调用函数即可。
例如,以下是一个使用"gettickcount"函数计算程序运行时间的示例:```c#include <stdio.h>#include <stdint.h>#include <time.h>uint32_t gettickcount(void){struct timespec ts;clock_gettime(CLOCK_MONOTONIC, &ts);uint32_t ticks = _sec * 1000 + _nsec / 1000000;return ticks;}int main(){uint32_t start_time = gettickcount();// 执行一些需要计时的操作uint32_t end_time = gettickcount();uint32_t elapsed_time = end_time - start_time;printf("程序运行时间:%u 毫秒\n", elapsed_time);return 0;}```在上述示例中,我们首先包含了相关的头文件。
作为系统调用而言,_exit和exit是一对孪生兄弟,它们究竟相似到什么程度,我们可以从Linux的源码中找到答案:"__NR_"是在Linux的源码中为每个系统调用加上的前缀,请注意第一个exit前有2条下划线,第二个exit前只有1条下划线。
这时随便一个懂得C语言并且头脑清醒的人都会说,_exit和exit没有任何区别,但我们还要讲一下这两者之间的区别,这种区别主要体现在它们在函数库中的定义。
_exit在Linux函数库中的原型是:和exit比较一下,exit()函数定义在stdlib.h中,而_exit()定义在unistd.h 中,从名字上看,stdlib.h似乎比 unistd.h高级一点,那么,它们之间到底有什么区别呢?_exit()函数的作用最为简单:直接使进程停止运行,清除其使用的内存空间,并销毁其在内核中的各种数据结构;exit() 函数则在这些基础上作了一些包装,在执行退出之前加了若干道工序,也是因为这个原因,有些人认为exit已经不能算是纯粹的系统调用。
exit()函数与_exit()函数最大的区别就在于exit()函数在调用exit系统调用之前要检查文件的打开情况,把文件缓冲区中的内容写回文件,就是"清理I/O 缓冲"。
在Linux的标准函数库中,有一套称作"高级I/O"的函数,我们熟知的printf()、fopen()、fread()、fwrite()都在此列,它们也被称作"缓冲I/O(buffered I/O)",其特征是对应每一个打开的文件,在内存中都有一片缓冲区,每次读文件时,会多读出若干条记录,这样下次读文件时就可以直接从内存的缓冲区中读取,每次写文件的时候,也仅仅是写入内存中的缓冲区,等满足了一定的条件(达到一定数量,或遇到特定字符,如换行符和文件结束符EOF),再将缓冲区中的内容一次性写入文件,这样就大大增加了文件读写的速度,但也为我们编程带来了一点点麻烦。
Linux下对文件操作有两种方式:系统调用(system call)和库函数调用(Library
functions) 0可以参考 紅inux程序设计》(英文原版为《Beginning Linux
Programming^ ,作者是 Neil Matthew 和 Richard Stones)第三章:Working with fi
1 eSo系统调用实际上就是指最底层的一个调用,在1 inux程序设计里面就是 底层
调用的意思。面向的是硬件。而库函数调用则面向的是应用开发的,相当 于应用程
序的api,采用这样的方式有很多种原因,第一:双缓冲技术的实现。 第二,可移植
性。第三,底层调用本身的一些性能方面的缺陷。第四:让api也 可以有了级别和
专门的工作面向。
1、系统调用
系统调用提供的函数如open, close, read, write, ioctl等,需包含头文件 unistd.
ho 以 write 为例:其函数原型为 size t write (int fd, const void *buf, size_t
nbytes),其操作对象为文件描述符或文件句柄fd(file descriptor), 要想写一个文
件,必须先以可写权限用open系统调用打开一个文件,获得所打 开文件的 fd,例如
fd=open(\7dev/video\〃, 0_RDWR) o fd 是一个整型值,每 新打开一个文件,所获
得的fd为当前最大fd加lo Linux系统默认分配了 3个 文件描述符 值:0 —standard
input, 1 — standard output, 2 —standard error0
系统调用通常用于底层文件访问(low-level file access),例如在驱动程序 中对设
备文件的直接访问。
系统调用是操作系统相关的,因此一般没有跨操作系统的可移植性。
系统调用发生在内核空间,因此如果在用户空间的一般应用程序中使用系统调用 来
进行文件操作,会有用户空间到内核空间切换的开销。事实上,即使在用户空 间使
用库函数来对文件进行操作,因为文件总是存在于存储介质上,因此不管是 读写操
作,都是对硬件(存储器)的操作,都必然会引起系统调用。也就是说, 库函数对文
件的操作实际上是通过系统调用來实现的。例如C库函数fwritcO 就是通过肌、ite()
系统调用来实现的。
这样的话,使用库函数也有系统调用的开销,为什么不直接使用系统调用呢?这 是
因为,读写文件通常是大量的数据(这种大量是相对于底层驱动的系统调用所 实现的
数据操作单位而言),这时,使用库函数就可以大大减少系统调用的次数。 这一结果
又缘于缓冲区技术。在用户空间和内核空间,对文件操作都使用了缓 冲区,例如用
fwrite写文件,都是先将内容写到用户空间缓冲区,当用户空间 缓冲区满或者写操
作结束时,才将用户缓冲区的内容写到内核缓冲区,同样的 道理,当内核缓冲区满
或写结束时才将内核缓冲区内容写到文件对应的硬件媒介。
2、库函数调用 标准C库函数提供的文件操作函数如fopen, fread, fwrite, fclose,
fflush, fseek等,需包含头文件stdio. ho以fwrite为例,其函数原型为size t
fwrite(const void *buffer, sizet size, sizet itemnum, FILE *pf), 其 操作
对象为文件指针FILE *pf,要禎写一个文件,—必须先以可写权限用fopen 函数打开
一个文件,获得所打开文件的FILE结构指针pf,例如 pf=fopen(\/,Vproj/filename\/,,
\,zw\,z) o实际上,由于库函数对文件的操作最 终是通过系统调用实现的,因此,
每打开一个文件所获得的FILE结构指针都有 一个内核空间的文件描述符fd与之对
应。同样有相应的预定义的FILE指针: std in — sta ndard in put, stdout —sta
ndard output, stderr —sta ndard error o
库函数调用通常用于应用程序屮对一般文件的访问。
库函数调用是系统无关的,因此可移植性好。
由于库函数调用是基于C库的,因此也就不可能用于内核空间的驱动程序中对设 备
的操作。
※函数库调用VS系统调用 函数库调用 在所有的ANSI C编译器版本中,C 库函数是相同的 它调用函数库屮的一段程序(或函 数) 与用户程序相联系 在用户地址空间执行 它的运行时间属于“用户时间” 属于过程调用,调用开销较小 在C函数库libc中有大约300个 系统调用 各个操作系统的系统调用是不同
的
它调用系统内核的服务
是操作系统的一个入口点
在内核地址空间执行
它的运行时间属于“系统”时间
需要在用户空间和内核上下文环
境间切换,开销较大
在UNIX中大约有90个系统调用
函数
典型的c函数库调用:
system 典型的系统调用:chdir fork