Linux 开发学习指南:函数调用详解与实战 (linux 调用函数怎么写)

Linux 是一个开放源代码操作系统,作为一名开发者,学会开发 Linux 系统是极为重要的。在 Linux 开发中,函数调用是最基础、最重要的一环。通过函数调用,我们可以实现各种各样的功能,从而完善 Linux 系统。本文将为大家详解 Linux 函数调用,包括调用过程、参数传递、实例演示等内容。

一、函数调用过程

在 Linux 开发中,函数调用遵循一定的规则,大体过程如下:

1. 将调用参数传递给被调用函数。传递参数时,如果参数是基本类型,则直接传递值;但如果是数组或结构体等复杂类型,需要传递地址。

2. 被调用函数使用传递的参数来执行相应的任务。

3. 可能会返回一个值给调用函数。

4. 调用函数使用返回值来完成自己的任务。

5. 调用函数通过堆栈(stack)来实现上述过程。在调用函数前,先将返回地址值(即调用函数时下一条指令的地址)压入堆栈;在函数执行完后,返回值从特定寄存器或内存中取出,并跳转到返回地址。

二、参数传递细节

1. 基本类型的参数传递:整形参数会被直接复制到被调用函数的栈帧中,而不是函数的参数列表中。同时,一个值的传递不会影响原来变量的值。例如:

“`

int a = 100;

int b = 200;

swap(a, b);// 不会改变a和b的值

“`

2. 数组和结构体的参数传递:与传递整型变量不同,数组和结构体类型的参数在传递时,实际上传递的是地址。例如:

“`

typedef struct{

int a;

int b;

}Point;

void setPoint(Point* p, int a, int b){

p->a = a;

p->b = b;

}

“`

在调用 setPoint 函数时,可以使用如下方式:

“`

Point p;

setPoint(&p, 1, 2);

“`

3. 可变参数函数(如 printf 函数)的参数传递:可变参数函数处理时,需要使用不定量参数列表(va_list)和相关宏或函数来获得参数的值。例如:

“`

#include

int sum(int num, …){

va_list valist;

int sum = 0;

va_start(valist, num);

for(int i = 0; i

sum += va_arg(valist, int);

}

va_end(valist);

return sum;

}

“`

三、实例演示

1. 获取用户输入并输出

“`

#include

int mn(){

char* buffer;

printf(“Input something: “);

buffer = get_input();

printf(“Your input: %s”, buffer);

return 0;

}

char* get_input(){

char* buffer = (char*)malloc(100);

scanf(“%s”, buffer);

return buffer;

}

“`

2. 简单排序

“`

#include

void bubble_sort(int arr[], int len);

void print_arr(int arr[], int len);

int mn(){

int len = 5;

int arr[] = {5, 4, 3, 2, 1};

printf(“before sort: “);

print_arr(arr, len);

bubble_sort(arr, len);

printf(“\nafter sort: “);

print_arr(arr, len);

return 0;

}

void bubble_sort(int arr[], int len){

int temp;

for(int i = 0; i

for(int j = 0; j

if(arr[j] > arr[j + 1]){

temp = arr[j];

arr[j] = arr[j + 1];

arr[j + 1] = temp;

}

}

}

}

void print_arr(int arr[], int len){

for(int i = 0; i

printf(“%d “, arr[i]);

}

}

“`

相关问题拓展阅读:

如何调用Linux内核函数

注意看这个文件

sysdeps/unix/sysv/linux/syscalls.list

里面记录着系统调用的名字和一些属性,具体我也没有研究过,不懂。

再看select的实现,很让人惊讶,一旦使用,结果就是“报错“。

int

__select (nfds, readfds, writefds, exceptfds, timeout)

int nfds;

fd_set *readfds;

fd_set *writefds;

fd_set *exceptfds;

struct timeval *timeout;

{

__set_errno (ENOSYS);

return -1;

}

libc_hidden_def (__select)

stub_warning (select)

weak_alias (__select, select)

这是因为glibc并没有实现系统调用,而是调用系统调用,

更进一步,连调用系统调用都没有一个锋蚂个实现,而是使用了通用的办法,

理由很简单,所有的系统调用在linux内核头文件里都能找到,

所有的系统调用参数类型就那么几种,参数个数也是有限的,

因此没有必要针对所有的系统调用一一封装,

于是就有了这个list文件,自动生成调用系统调用的函数,

如果生成失败,也就是你看到的“报错”。

符号是有强弱的,当自掘租动生成成功的时候,“报错”的弱符号就被忽略了。

当你在glibc中找到判基兆一个系统调用的封装源码,是以下原因,

1. 编译的目标系统不支持这个系统调用,所以自己用另一种方式实现了。

2. 这个系统调用无法使用通用的自动生成方式生成,用特化的方式覆盖。

3. 针对这个系统调用做了特别的优化。

4. 其它可能的原因。

具体可以留意

SYSCALL, PSEUDO, DO_CALL, INLINE_CALL 等名字

这两个文件是重点所在

sysdeps/unix/i386/sysdep.h

sysdeps/unix/i386/sysdep.S

要搞清楚具体的自动生成过程,恐怕得研究glibc自身的编译过程了

linux 怎样调用daemon库函数

守护进程(Daemon)是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。守护进程是一种很有用的进 程。Linux的核瞎模大多数服务器就是用守护进程实现的。比如,Internet服务器inetd,Web服务器httpd等。同时,守护进程完成许多系统任 务。比如,作业规划进程crond,打印进程lpd等。

守护进程的编程本身并不复杂,复杂的是各种版本的Unix的实现机制不尽相同,造成不同Unix环境下守护进程的编程规则并不一致。这需要读者注意,照搬 某些书上的规则(特别是BSD4.3和低版本的System V)到Linux会出现错误的。下面将全面介绍Linux下守护进程的编程要点并给出详细实例。

一. 守护进程及其特性

守护进程最重要的特性是后台运行。在这一点上DOS下的常驻内存程序TSR与之相似。其次,守护进程必须与其运行前的环境隔离开来。这些环境包括未关闭的 文件描述符,控制终端,会话和进程组,工作目录以及文件创建掩模等。这些环境通常是守护进程从执行它的父进程(特别是shell)中继承下来的。最后,守 护进程的启动方式有其特殊之处。它可以在Linux系统启动时从启动脚本/etc/rc.d中启动,可以由作业规划进程crond启动,还可以由用户终端 (通常是shell)执行。

总之,除开这些特殊性以外,守护进程与普通进程基本上没有什么区别。因此,编写守护进程实际上是把一个普通进改缓程按照上述的守护进程的特性改造成为守护进程。如果读者对进程有比较深入的认识就更容易理解和编程了。

二. 守护进程的编程要点

前面讲过,不同Unix环境下守护进程的编程规则并不一致。所幸的是守护进程的编程原则其实都一样,区别在于具体的实现细节不同。这个原则就是要满足守护 进程的特性。同时,Linux是基于Syetem V的SVR4并遵循Posix标准,实现起来与BSD4相比更方便。编程要点如下;

1. 在后台运行。

为避免挂起控制终端将Daemon放入后台执行。方法是在进程中调用fork使父进程终止,让Daemon在子进程中后台执行。

if(pid=fork())

exit(0);//是父进程,结束父进程,子进程继续

2. 脱离控制终端,登录会话和进程组

有必要先介绍一下Linux中的进程与控制终端,登录会话和进程组之间的关系:进程属于一个进程组,进程组号(GID)就是进程组长的进程号(PID)。登录会话可以包含多个进程组。这些进程组共享一个控制终端。这个控制终端通常是创建进程的登录终端。

控制终端,登录会话和进程组通常是从父进程继承下来的。我们的目的就是要摆脱它们,使之不受它们的影响神郑。方法是在第1点的基础上,调用setsid()使进程成为会话组长:

setsid();

说明:当进程是会话组长时setsid()调用失败。但之一点已经保证进程不是会话组长。setsid()调用成功后,进程成为新的会话组长和新的进程组长,并与原来的登录会话和进程组脱离。由于会话过程对控制终端的独占性,进程同时与控制终端脱离。

3. 禁止进程重新打开控制终端

现在,进程已经成为无终端的会话组长。但它可以重新申请打开一个控制终端。可以通过使进程不再成为会话组长来禁止进程重新打开控制终端:

if(pid=fork())

exit(0);//结束之一子进程,第二子进程继续(第二子进程不再是会话组长)

4. 关闭打开的文件描述符

进程从创建它的父进程那里继承了打开的文件描述符。如不关闭,将会浪费系统资源,造成进程所在的文件系统无法卸下以及引起无法预料的错误。按如下方法关闭它们:

for(i=0;i 关闭打开的文件描述符close(i);>

for(i=0;i

#include

#include

#include

#include

void init_daemon(void)

{

int pid;

int i;

if(pid=fork())

exit(0);//是父进程,结束父进程

else if(pid

#include

void init_daemon(void);//守护进程初始化函数

main()

{

FILE *fp;

time_t t;

init_daemon();//初始化为Daemon

while(1)//每隔一分钟向test.log报告运行状态

{

sleep(60);//睡眠一分钟

if((fp=fopen(“test.log”,”a”)) >=0)

{

t=time(0);

fprintf(fp,”I’m here at %sn”,asctime(localtime(&t)) );

fclose(fp);

}

}

}

以上程序在RedHat Linux6.0下编译通过。步骤如下:

编译:gcc –g –o test init.c test.c

执行:./test

查看进程:ps –ef

从输出可以发现test守护进程的各种特性满足上面的要求。

linux 调用函数怎么写的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于linux 调用函数怎么写,Linux 开发学习指南:函数调用详解与实战,如何调用Linux内核函数,linux 怎样调用daemon库函数的信息别忘了在本站进行查找喔。


数据运维技术 » Linux 开发学习指南:函数调用详解与实战 (linux 调用函数怎么写)