目录
1.signal函数
signal函数也是用于信号处理的函数,它可以用来注册信号处理函数、忽略信号或恢复信号默认处理方式等。C语言的signal函数与Python中的signal函数类似,但有一些细微的差别。
signal函数的使用方法如下:
-
包含头文件:
#include <signal.h>
-
定义信号处理函数,函数的格式为
void handler(int signum)
,其中signum
表示信号编号。 -
使用signal函数注册信号处理函数:
void (*signal(int signum, void (*handler)(int)))(int)
,其中signum
表示要注册的信号编号,handler
表示信号处理函数。
例如,如果要在程序中捕获键盘中断信号(SIGINT),可以使用以下代码:
#include <stdio.h>
#include <signal.h>
// 定义信号处理函数
void handler(int signum) {
printf("收到信号:%d\n", signum);
}
int main() {
// 注册信号处理函数
signal(SIGINT, handler);
// 等待信号
printf("等待信号...\n");
pause();
return 0;
}
等待信号...
^C收到信号:2
在执行程序时,按下Ctrl+C
键即可发送键盘中断信号,程序会输出收到信号的信息。
需要注意的是,C语言的signal函数在使用时可能存在一些平台差异和不确定性,因此在实际开发中,可以考虑使用更可靠的信号处理方式,如sigaction函数。
2.glob函数
C语言中没有内置的glob函数,但可以通过使用第三方库来实现类似的功能。一个常用的库是glob.h
,它提供了用于文件名模式匹配的函数。
使用glob.h
库进行文件名模式匹配的基本步骤如下:
-
包含头文件:
#include <glob.h>
-
创建一个
glob_t
结构体变量,用于保存匹配到的文件路径。 -
使用
glob
函数进行文件名模式匹配,函数原型为int glob(const char *pattern, int flags, int (*errfunc) (const char *epath, int eerrno), glob_t *pglob)
,其中pattern
表示要匹配的文件名模式,flags
表示匹配的选项,errfunc
表示错误处理函数,pglob
表示保存匹配结果的结构体变量。 -
使用
glob
函数成功返回0,可以通过访问pglob
结构体变量的gl_pathv
成员来获取匹配到的文件路径。 -
使用完后,记得使用
globfree
函数释放pglob
结构体变量的内存。
下面是一个简单的示例代码,演示了如何使用glob.h
库进行文件名模式匹配:
#include <stdio.h>
#include <glob.h>
int main() {
glob_t glob_result;
int ret = glob("*.txt", 0, NULL, &glob_result);
if (ret == 0) {
for (int i = 0; i < glob_result.gl_pathc; i++) {
printf("%s\n", glob_result.gl_pathv[i]);
}
} else {
printf("匹配失败\n");
}
globfree(&glob_result);
return 0;
}
file1.txt
file2.txt
file3.txt
需要注意的是,使用glob.h
库进行文件名模式匹配时,需要确保正确包含并链接该库。另外,不同平台上的glob.h
库的行为和特性可能有所差异,因此在实际开发中,需要注意相关的平台兼容性问题。
3.atexit函数
在C语言中,atexit
函数用于注册一个函数,在程序正常退出时自动调用该函数。它可以用来执行一些清理工作,例如关闭文件、释放内存等。
atexit
函数的使用方法如下:
-
包含头文件:
#include <stdlib.h>
-
定义清理函数,函数的格式为
void cleanup(void)
。 -
使用
atexit
函数注册清理函数:int atexit(void (*cleanup)(void))
,其中cleanup
表示清理函数。
例如,如果要在程序退出时关闭一个文件,可以使用以下代码:
#include <stdio.h>
#include <stdlib.h>
// 清理函数
void cleanup(void) {
printf("执行清理工作\n");
// 关闭文件等清理操作
fclose(file);
}
int main() {
// 打开文件等初始化操作
FILE *file = fopen("file.txt", "r");
// 注册清理函数
atexit(cleanup);
// 其他代码...
return 0;
}
在程序正常退出时,cleanup
函数会被自动调用,执行清理工作。
需要注意的是,atexit
函数可以注册多个清理函数,它们会按照注册的顺序逆序执行。当程序退出时,所有已注册的清理函数都会被调用。
此外,atexit
函数的返回值为0表示成功,非零值表示失败。如果注册的清理函数过多超过系统定义的限制,可能会导致注册失败。
另外,需要注意的是,atexit
函数只在程序正常退出时调用注册的清理函数,如果程序异常终止(如通过exit
函数或信号终止),则不会调用注册的清理函数。如果需要在异常终止时也执行清理操作,可以考虑使用signal
函数来注册信号处理函数。
4.fork函数
fork
函数用于创建一个新的进程,该进程是原始进程的副本。fork
函数的原型如下:
#include <unistd.h>
pid_t fork(void);
fork
函数调用时会创建一个新的进程,该进程与原始进程几乎完全相同,包括代码、数据、堆栈等。新创建的进程被称为子进程,原始进程被称为父进程。fork
函数的返回值不同于其他函数,它返回两次,分别在父进程和子进程中返回。
- 在父进程中,
fork
函数返回子进程的进程ID(PID),可以通过该值判断当前进程是父进程还是子进程。如果fork
函数返回值为负数,表示创建子进程失败。 - 在子进程中,
fork
函数返回0。
下面是一个简单的示例代码,演示了fork
函数的使用:
#include <stdio.h>
#include <unistd.h>
int main() {
pid_t pid = fork();
if (pid < 0) {
// 创建子进程失败
printf("创建子进程失败\n");
} else if (pid == 0) {
// 子进程
printf("这是子进程,进程ID:%d\n", getpid());
} else {
// 父进程
printf("这是父进程,进程ID:%d,子进程ID:%d\n", getpid(), pid);
}
return 0;
}
运行结果:
这是父进程,进程ID:1234,子进程ID:1235
这是子进程,进程ID:1235
需要注意的是,子进程是父进程的副本,它们共享同一份代码和数据。但是,子进程会从fork
函数的返回处开始执行,而不是从原始进程的调用点开始执行。因此,父进程和子进程之间可以通过返回值来区分自己的身份。
此外,fork
函数的调用会复制父进程的文件描述符、信号处理器等状态。但是,父进程和子进程之间的文件描述符是独立的,它们之间的文件操作不会相互影响。
在实际开发中,fork
函数常用于创建子进程来并行执行某些任务,例如服务器程序中的多进程并发处理、进程池等。同时,需要注意在使用fork
函数时,要避免产生僵尸进程和孤儿进程等问题,可以使用wait
或waitpid
函数来等待子进程的退出,或者使用信号处理函数来处理子进程的退出信号。
5.execlp函数
execlp
函数用于在当前进程中执行一个新的程序。execlp
函数的原型如下:
#include <unistd.h>
int execlp(const char *file, const char *arg, ...);
execlp
函数的第一个参数file
是要执行的程序的文件名或路径。第二个参数arg
是要传递给新程序的命令行参数,后面可以跟多个参数,用于传递给新程序的命令行参数。最后一个参数必须是一个空指针,表示参数列表的结束。
execlp
函数会将当前进程替换为新的程序,新程序从main
函数开始执行。因此,execlp
函数调用成功后,原来的进程代码和数据都会被新程序替换,原来的进程的执行流程不会继续。
下面是一个简单的示例代码,演示了execlp
函数的使用:
#include <stdio.h>
#include <unistd.h>
int main() {
printf("这是原始程序\n");
// 执行ls命令
execlp("ls", "ls", "-l", NULL);
// 如果execlp执行成功,下面的代码不会被执行
printf("execlp执行失败\n");
return 0;
}
结果:
这是原始程序
total 8
-rwxrwxr-x 1 user user 8608 Jan 1 10:00 a.out
execlp
函数调用成功后,原始程序的代码和数据都会被新程序替换。因此,如果execlp
函数执行成功,后面的代码将不会被执行。
需要注意的是,execlp
函数会搜索系统的PATH
环境变量,找到要执行的程序的路径。因此,可以直接指定程序的名字,而不需要写出完整的路径。
另外,execlp
函数的返回值只有在调用失败时才会返回,如果函数执行成功,它不会返回。如果execlp
函数执行失败,它会返回-1,并且设置errno
变量来指示错误的原因。常见的错误包括文件不存在、权限不足等。
execlp
函数还有其他几个变种,如execvp
、execle
、execv
等,它们的参数和功能略有不同,但基本用法相似。这些函数在实际开发中常用于进程的替换和程序的动态加载等场景。