第16章 系统函数库
1. 系统函数库概述
1.1 什么是系统函数库
系统函数库是操作系统提供的一组函数集合,用于访问系统功能和资源。这些函数封装了底层的系统调用,为应用程序提供了一个统一的接口,使应用程序能够与操作系统进行交互。
1.2 系统函数库的分类
C语言中的系统函数库主要包括:
- 标准I/O库:用于文件输入/输出操作
- 字符串处理库:用于字符串操作
- 数学库:用于数学计算
- 时间和日期库:用于时间和日期操作
- 内存分配库:用于动态内存分配
- 进程控制库:用于进程管理
- 网络编程库:用于网络通信
- 信号处理库:用于信号处理
- 线程编程库:用于多线程编程
- 系统调用库:用于直接调用系统服务
1.3 系统函数库的使用
使用系统函数库需要:
- 包含相应的头文件:如
#include <stdio.h> - 链接相应的库:如使用
-lm链接数学库 - 遵循函数的调用约定:正确传递参数,处理返回值
2. 标准I/O库
2.1 标准I/O库概述
标准I/O库(<stdio.h>)提供了文件输入/输出操作的函数,是C语言中最常用的库之一。
2.2 常用函数
2.2.1 文件操作函数
| 函数名 | 功能 | 原型 |
|---|
fopen | 打开文件 | FILE *fopen(const char *filename, const char *mode); |
fclose | 关闭文件 | int fclose(FILE *stream); |
fread | 读取文件 | size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); |
fwrite | 写入文件 | size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); |
fseek | 设置文件位置 | int fseek(FILE *stream, long offset, int whence); |
ftell | 获取文件位置 | long ftell(FILE *stream); |
rewind | 重置文件位置 | void rewind(FILE *stream); |
feof | 检查文件结束 | int feof(FILE *stream); |
ferror | 检查文件错误 | int ferror(FILE *stream); |
clearerr | 清除文件错误 | void clearerr(FILE *stream); |
2.2.2 格式化输入/输出函数
| 函数名 | 功能 | 原型 |
|---|
printf | 格式化输出到标准输出 | int printf(const char *format, ...); |
scanf | 格式化输入到标准输入 | int scanf(const char *format, ...); |
fprintf | 格式化输出到文件 | int fprintf(FILE *stream, const char *format, ...); |
fscanf | 格式化输入到文件 | int fscanf(FILE *stream, const char *format, ...); |
sprintf | 格式化输出到字符串 | int sprintf(char *str, const char *format, ...); |
sscanf | 格式化输入到字符串 | int sscanf(const char *str, const char *format, ...); |
snprintf | 安全的格式化输出到字符串 | int snprintf(char *str, size_t size, const char *format, ...); |
2.2.3 字符输入/输出函数
| 函数名 | 功能 | 原型 |
|---|
getchar | 从标准输入读取字符 | int getchar(void); |
putchar | 向标准输出写入字符 | int putchar(int c); |
fgetc | 从文件读取字符 | int fgetc(FILE *stream); |
fputc | 向文件写入字符 | int fputc(int c, FILE *stream); |
ungetc | 放回字符到输入流 | int ungetc(int c, FILE *stream); |
2.2.4 字符串输入/输出函数
| 函数名 | 功能 | 原型 |
|---|
gets | 从标准输入读取字符串(不安全) | char *gets(char *s); |
puts | 向标准输出写入字符串 | int puts(const char *s); |
fgets | 从文件读取字符串 | char *fgets(char *s, int size, FILE *stream); |
fputs | 向文件写入字符串 | int fputs(const char *s, FILE *stream); |
2.3 使用示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| #include <stdio.h>
int main() { FILE *fp; char buffer[100]; fp = fopen("example.txt", "w+"); if (fp == NULL) { perror("fopen"); return 1; } fprintf(fp, "Hello, world!\n"); fprintf(fp, "This is a test.\n"); rewind(fp); while (fgets(buffer, sizeof(buffer), fp) != NULL) { printf("%s", buffer); } fclose(fp); return 0; }
|
3. 字符串处理库
3.1 字符串处理库概述
字符串处理库(<string.h>)提供了字符串操作的函数,是C语言中最常用的库之一。
3.2 常用函数
3.2.1 字符串操作函数
| 函数名 | 功能 | 原型 |
|---|
strlen | 获取字符串长度 | size_t strlen(const char *s); |
strcpy | 复制字符串(不安全) | char *strcpy(char *dest, const char *src); |
strncpy | 安全的复制字符串 | char *strncpy(char *dest, const char *src, size_t n); |
strcat | 连接字符串(不安全) | char *strcat(char *dest, const char *src); |
strncat | 安全的连接字符串 | char *strncat(char *dest, const char *src, size_t n); |
strcmp | 比较字符串 | int strcmp(const char *s1, const char *s2); |
strncmp | 比较字符串前n个字符 | int strncmp(const char *s1, const char *s2, size_t n); |
strchr | 查找字符 | char *strchr(const char *s, int c); |
strrchr | 反向查找字符 | char *strrchr(const char *s, int c); |
strstr | 查找子字符串 | char *strstr(const char *haystack, const char *needle); |
strtok | 分割字符串 | char *strtok(char *str, const char *delim); |
memset | 填充内存 | void *memset(void *s, int c, size_t n); |
memcpy | 复制内存 | void *memcpy(void *dest, const void *src, size_t n); |
memmove | 安全的复制内存 | void *memmove(void *dest, const void *src, size_t n); |
memcmp | 比较内存 | int memcmp(const void *s1, const void *s2, size_t n); |
3.3 使用示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| #include <stdio.h> #include <string.h>
int main() { char str1[50] = "Hello, "; char str2[] = "world!"; char str3[50]; strcat(str1, str2); printf("str1: %s\n", str1); strcpy(str3, str1); printf("str3: %s\n", str3); if (strcmp(str1, str3) == 0) { printf("str1 and str3 are equal\n"); } printf("Length of str1: %zu\n", strlen(str1)); char *ptr = strstr(str1, "world"); if (ptr != NULL) { printf("Found 'world' at position: %ld\n", ptr - str1); } return 0; }
|
4. 数学库
4.1 数学库概述
数学库(<math.h>)提供了数学计算的函数,使用时需要链接数学库(-lm)。
4.2 常用函数
4.2.1 基本数学函数
| 函数名 | 功能 | 原型 |
|---|
sin | 正弦函数 | double sin(double x); |
cos | 余弦函数 | double cos(double x); |
tan | 正切函数 | double tan(double x); |
asin | 反正弦函数 | double asin(double x); |
acos | 反余弦函数 | double acos(double x); |
atan | 反正切函数 | double atan(double x); |
atan2 | 反正切函数(两个参数) | double atan2(double y, double x); |
sinh | 双曲正弦函数 | double sinh(double x); |
cosh | 双曲余弦函数 | double cosh(double x); |
tanh | 双曲正切函数 | double tanh(double x); |
4.2.2 指数和对数函数
| 函数名 | 功能 | 原型 |
|---|
exp | 指数函数 | double exp(double x); |
log | 自然对数 | double log(double x); |
log10 | 以10为底的对数 | double log10(double x); |
pow | 幂函数 | double pow(double x, double y); |
sqrt | 平方根 | double sqrt(double x); |
cbrt | 立方根 | double cbrt(double x); |
4.2.3 取整和绝对值函数
| 函数名 | 功能 | 原型 |
|---|
ceil | 向上取整 | double ceil(double x); |
floor | 向下取整 | double floor(double x); |
round | 四舍五入 | double round(double x); |
fabs | 绝对值 | double fabs(double x); |
abs | 整数绝对值 | int abs(int x); |
labs | 长整数绝对值 | long labs(long x); |
llabs | 长 long 整数绝对值 | long long llabs(long long x); |
4.3 使用示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| #include <stdio.h> #include <math.h>
int main() { double x = 1.0; double y = 2.0; printf("sin(1.0) = %f\n", sin(x)); printf("cos(1.0) = %f\n", cos(x)); printf("tan(1.0) = %f\n", tan(x)); printf("exp(1.0) = %f\n", exp(x)); printf("log(1.0) = %f\n", log(x)); printf("pow(2.0, 3.0) = %f\n", pow(y, 3.0)); printf("sqrt(4.0) = %f\n", sqrt(y * y)); printf("ceil(1.5) = %f\n", ceil(1.5)); printf("floor(1.5) = %f\n", floor(1.5)); printf("round(1.5) = %f\n", round(1.5)); printf("fabs(-1.5) = %f\n", fabs(-1.5)); return 0; }
|
5. 时间和日期库
5.1 时间和日期库概述
时间和日期库(<time.h>)提供了时间和日期操作的函数。
5.2 常用函数
5.2.1 时间操作函数
| 函数名 | 功能 | 原型 |
|---|
time | 获取当前时间 | time_t time(time_t *t); |
ctime | 转换时间为字符串 | char *ctime(const time_t *t); |
asctime | 转换结构体为字符串 | char *asctime(const struct tm *tm); |
localtime | 转换时间为本地时间 | struct tm *localtime(const time_t *t); |
gmtime | 转换时间为GMT时间 | struct tm *gmtime(const time_t *t); |
mktime | 转换结构体为时间 | time_t mktime(struct tm *tm); |
difftime | 计算时间差 | double difftime(time_t time1, time_t time0); |
strftime | 格式化时间为字符串 | size_t strftime(char *s, size_t maxsize, const char *format, const struct tm *tm); |
5.3 使用示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| #include <stdio.h> #include <time.h>
int main() { time_t current_time; struct tm *local_time; char time_string[50]; current_time = time(NULL); printf("Current time: %ld\n", current_time); local_time = localtime(¤t_time); strftime(time_string, sizeof(time_string), "%Y-%m-%d %H:%M:%S", local_time); printf("Formatted time: %s\n", time_string); printf("ctime: %s", ctime(¤t_time)); return 0; }
|
6. 内存分配库
6.1 内存分配库概述
内存分配库(<stdlib.h>)提供了动态内存分配的函数,是C语言中管理内存的重要工具。
6.2 常用函数
6.2.1 内存分配函数
| 函数名 | 功能 | 原型 |
|---|
malloc | 分配内存 | void *malloc(size_t size); |
calloc | 分配并清零内存 | void *calloc(size_t nmemb, size_t size); |
realloc | 重新分配内存 | void *realloc(void *ptr, size_t size); |
free | 释放内存 | void free(void *ptr); |
aligned_alloc | 分配对齐内存 | void *aligned_alloc(size_t alignment, size_t size); |
6.2.2 其他常用函数
| 函数名 | 功能 | 原型 |
|---|
exit | 终止程序 | void exit(int status); |
atoi | 字符串转整数 | int atoi(const char *nptr); |
atol | 字符串转长整数 | long atol(const char *nptr); |
atoll | 字符串转长 long 整数 | long long atoll(const char *nptr); |
strtod | 字符串转双精度浮点数 | double strtod(const char *nptr, char **endptr); |
strtol | 字符串转长整数 | long strtol(const char *nptr, char **endptr, int base); |
strtoll | 字符串转长 long 整数 | long long strtoll(const char *nptr, char **endptr, int base); |
rand | 生成随机数 | int rand(void); |
srand | 设置随机数种子 | void srand(unsigned int seed); |
qsort | 快速排序 | void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)); |
bsearch | 二分查找 | void *bsearch(const void *key, const void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)); |
6.3 使用示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| #include <stdio.h> #include <stdlib.h>
int compare(const void *a, const void *b) { return (*(int *)a - *(int *)b); }
int main() { int *arr; int n = 5; int i; arr = (int *)malloc(n * sizeof(int)); if (arr == NULL) { perror("malloc"); return 1; } srand(time(NULL)); for (i = 0; i < n; i++) { arr[i] = rand() % 100; printf("arr[%d] = %d\n", i, arr[i]); } qsort(arr, n, sizeof(int), compare); printf("Sorted array:\n"); for (i = 0; i < n; i++) { printf("arr[%d] = %d\n", i, arr[i]); } free(arr); return 0; }
|
7. 进程控制库
7.1 进程控制库概述
进程控制库(<unistd.h>)提供了进程管理的函数,主要用于Unix-like系统。
7.2 常用函数
| 函数名 | 功能 | 原型 |
|---|
fork | 创建子进程 | pid_t fork(void); |
exec 系列 | 执行程序 | 如 int execl(const char *path, const char *arg, ...); |
wait | 等待子进程结束 | pid_t wait(int *status); |
waitpid | 等待指定子进程结束 | pid_t waitpid(pid_t pid, int *status, int options); |
getpid | 获取进程ID | pid_t getpid(void); |
getppid | 获取父进程ID | pid_t getppid(void); |
sleep | 睡眠指定秒数 | unsigned int sleep(unsigned int seconds); |
usleep | 睡眠指定微秒数 | int usleep(useconds_t usec); |
nanosleep | 睡眠指定纳秒数 | int nanosleep(const struct timespec *req, struct timespec *rem); |
getuid | 获取用户ID | uid_t getuid(void); |
geteuid | 获取有效用户ID | uid_t geteuid(void); |
getgid | 获取组ID | gid_t getgid(void); |
getegid | 获取有效组ID | gid_t getegid(void); |
chdir | 改变当前目录 | int chdir(const char *path); |
getcwd | 获取当前目录 | char *getcwd(char *buf, size_t size); |
unlink | 删除文件 | int unlink(const char *pathname); |
rename | 重命名文件 | int rename(const char *oldpath, const char *newpath); |
7.3 使用示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| #include <stdio.h> #include <unistd.h> #include <sys/wait.h>
int main() { pid_t pid; pid = fork(); if (pid < 0) { perror("fork"); return 1; } else if (pid == 0) { printf("Child process: PID = %d, PPID = %d\n", getpid(), getppid()); sleep(1); printf("Child process exiting\n"); return 0; } else { int status; printf("Parent process: PID = %d, Child PID = %d\n", getpid(), pid); wait(&status); printf("Parent process: Child exited with status %d\n", WEXITSTATUS(status)); return 0; } }
|
8. 网络编程库
8.1 网络编程库概述
网络编程库(<sys/socket.h>)提供了网络通信的函数,是C语言中进行网络编程的基础。
8.2 常用函数
8.2.1 套接字函数
| 函数名 | 功能 | 原型 |
|---|
socket | 创建套接字 | int socket(int domain, int type, int protocol); |
bind | 绑定地址 | int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); |
listen | 监听连接 | int listen(int sockfd, int backlog); |
accept | 接受连接 | int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); |
connect | 连接服务器 | int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); |
send | 发送数据 | ssize_t send(int sockfd, const void *buf, size_t len, int flags); |
recv | 接收数据 | ssize_t recv(int sockfd, void *buf, size_t len, int flags); |
sendto | 发送数据(UDP) | ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); |
recvfrom | 接收数据(UDP) | ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen); |
close | 关闭套接字 | int close(int fd); |
getaddrinfo | 获取地址信息 | int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res); |
freeaddrinfo | 释放地址信息 | void freeaddrinfo(struct addrinfo *res); |
inet_ntop | 网络地址转字符串 | const char *inet_ntop(int af, const void *src, char *dst, socklen_t size); |
inet_pton | 字符串转网络地址 | int inet_pton(int af, const char *src, void *dst); |
8.3 使用示例
服务器端:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h>
#define PORT 8080 #define BUFFER_SIZE 1024
int main() { int server_fd, new_socket; struct sockaddr_in address; int opt = 1; int addrlen = sizeof(address); char buffer[BUFFER_SIZE] = {0}; char *hello = "Hello from server"; if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { perror("socket failed"); exit(EXIT_FAILURE); } if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) { perror("setsockopt"); exit(EXIT_FAILURE); } address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons(PORT); if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) { perror("bind failed"); exit(EXIT_FAILURE); } if (listen(server_fd, 3) < 0) { perror("listen"); exit(EXIT_FAILURE); } if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) { perror("accept"); exit(EXIT_FAILURE); } read(new_socket, buffer, BUFFER_SIZE); printf("Client: %s\n", buffer); send(new_socket, hello, strlen(hello), 0); printf("Hello message sent\n"); close(new_socket); close(server_fd); return 0; }
|
客户端:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h>
#define PORT 8080 #define BUFFER_SIZE 1024
int main() { int sock = 0; struct sockaddr_in serv_addr; char buffer[BUFFER_SIZE] = {0}; char *hello = "Hello from client"; if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { printf("Socket creation error\n"); return -1; } serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(PORT); if(inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)<=0) { printf("Invalid address\n"); return -1; } if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { printf("Connection Failed\n"); return -1; } send(sock, hello, strlen(hello), 0); printf("Hello message sent\n"); read(sock, buffer, BUFFER_SIZE); printf("Server: %s\n", buffer); close(sock); return 0; }
|
9. 信号处理库
9.1 信号处理库概述
信号处理库(<signal.h>)提供了信号处理的函数,用于处理系统发送的各种信号。
9.2 常用函数
| 函数名 | 功能 | 原型 |
|---|
signal | 设置信号处理函数 | void (*signal(int signum, void (*handler)(int)))(int); |
sigaction | 设置信号处理函数(更灵活) | int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); |
kill | 发送信号 | int kill(pid_t pid, int sig); |
raise | 向自身发送信号 | int raise(int sig); |
alarm | 设置闹钟 | unsigned int alarm(unsigned int seconds); |
pause | 暂停进程直到信号到达 | int pause(void); |
sigprocmask | 阻塞/解除阻塞信号 | int sigprocmask(int how, const sigset_t *set, sigset_t *oldset); |
sigemptyset | 初始化信号集为空 | int sigemptyset(sigset_t *set); |
sigfillset | 初始化信号集为所有信号 | int sigfillset(sigset_t *set); |
sigaddset | 向信号集添加信号 | int sigaddset(sigset_t *set, int signum); |
sigdelset | 从信号集删除信号 | int sigdelset(sigset_t *set, int signum); |
sigismember | 检查信号是否在信号集中 | int sigismember(const sigset_t *set, int signum); |
9.3 使用示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| #include <stdio.h> #include <signal.h> #include <unistd.h>
void signal_handler(int signum) { printf("Received signal %d\n", signum); if (signum == SIGINT) { printf("Ctrl+C pressed, exiting...\n"); _exit(0); } }
int main() { signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); printf("Waiting for signals... (Press Ctrl+C to exit)\n"); while (1) { sleep(1); printf("Still waiting...\n"); } return 0; }
|
10. 线程编程库
10.1 线程编程库概述
线程编程库(<pthread.h>)提供了多线程编程的函数,使用时需要链接线程库(-lpthread)。
10.2 常用函数
| 函数名 | 功能 | 原型 |
|---|
pthread_create | 创建线程 | int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg); |
pthread_join | 等待线程结束 | int pthread_join(pthread_t thread, void **retval); |
pthread_detach | 分离线程 | int pthread_detach(pthread_t thread); |
pthread_exit | 终止线程 | void pthread_exit(void *retval); |
pthread_self | 获取线程ID | pthread_t pthread_self(void); |
pthread_equal | 比较线程ID | int pthread_equal(pthread_t t1, pthread_t t2); |
pthread_mutex_init | 初始化互斥锁 | int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr); |
pthread_mutex_lock | 加锁 | int pthread_mutex_lock(pthread_mutex_t *mutex); |
pthread_mutex_trylock | 尝试加锁 | int pthread_mutex_trylock(pthread_mutex_t *mutex); |
pthread_mutex_unlock | 解锁 | int pthread_mutex_unlock(pthread_mutex_t *mutex); |
pthread_mutex_destroy | 销毁互斥锁 | int pthread_mutex_destroy(pthread_mutex_t *mutex); |
pthread_cond_init | 初始化条件变量 | int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr); |
pthread_cond_wait | 等待条件变量 | int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); |
pthread_cond_signal | 唤醒一个等待的线程 | int pthread_cond_signal(pthread_cond_t *cond); |
pthread_cond_broadcast | 唤醒所有等待的线程 | int pthread_cond_broadcast(pthread_cond_t *cond); |
pthread_cond_destroy | 销毁条件变量 | int pthread_cond_destroy(pthread_cond_t *cond); |
10.3 使用示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| #include <stdio.h> #include <pthread.h> #include <unistd.h>
#define NUM_THREADS 5
pthread_mutex_t mutex; int counter = 0;
void *thread_function(void *arg) { int thread_id = *((int *)arg); pthread_mutex_lock(&mutex); counter++; printf("Thread %d: counter = %d\n", thread_id, counter); pthread_mutex_unlock(&mutex); pthread_exit(NULL); }
int main() { pthread_t threads[NUM_THREADS]; int thread_ids[NUM_THREADS]; int i; pthread_mutex_init(&mutex, NULL); for (i = 0; i < NUM_THREADS; i++) { thread_ids[i] = i; if (pthread_create(&threads[i], NULL, thread_function, &thread_ids[i]) != 0) { perror("pthread_create"); return 1; } } for (i = 0; i < NUM_THREADS; i++) { if (pthread_join(threads[i], NULL) != 0) { perror("pthread_join"); return 1; } } pthread_mutex_destroy(&mutex); printf("Final counter value: %d\n", counter); return 0; }
|
11. 系统调用库
11.1 系统调用库概述
系统调用库(<sys/syscall.h>)提供了直接调用系统服务的函数,是操作系统与应用程序之间的接口。
11.2 常用函数
| 函数名 | 功能 | 原型 |
|---|
syscall | 直接调用系统调用 | long syscall(long number, ...); |
read | 读取文件 | ssize_t read(int fd, void *buf, size_t count); |
write | 写入文件 | ssize_t write(int fd, const void *buf, size_t count); |
open | 打开文件 | int open(const char *pathname, int flags, mode_t mode); |
close | 关闭文件 | int close(int fd); |
lseek | 设置文件位置 | off_t lseek(int fd, off_t offset, int whence); |
mkdir | 创建目录 | int mkdir(const char *pathname, mode_t mode); |
rmdir | 删除目录 | int rmdir(const char *pathname); |
chmod | 修改文件权限 | int chmod(const char *pathname, mode_t mode); |
chown | 修改文件所有者 | int chown(const char *pathname, uid_t owner, gid_t group); |
link | 创建硬链接 | int link(const char *oldpath, const char *newpath); |
symlink | 创建符号链接 | int symlink(const char *target, const char *linkpath); |
readlink | 读取符号链接 | ssize_t readlink(const char *pathname, char *buf, size_t bufsiz); |
unlink | 删除文件 | int unlink(const char *pathname); |
rename | 重命名文件 | int rename(const char *oldpath, const char *newpath); |
11.3 使用示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| #include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <sys/stat.h>
int main() { int fd; char buffer[100]; ssize_t n; fd = open("example.txt", O_CREAT | O_WRONLY | O_TRUNC, 0644); if (fd < 0) { perror("open"); return 1; } n = write(fd, "Hello, world!\n", 13); if (n < 0) { perror("write"); close(fd); return 1; } close(fd); fd = open("example.txt", O_RDONLY); if (fd < 0) { perror("open"); return 1; } n = read(fd, buffer, sizeof(buffer)); if (n < 0) { perror("read"); close(fd); return 1; } write(STDOUT_FILENO, buffer, n); close(fd); return 0; }
|
12. 系统函数库的最佳实践
12.1 一般原则
- 包含正确的头文件:确保包含了所有需要的头文件
- 链接必要的库:如数学库(
-lm)、线程库(-lpthread)等 - 检查函数返回值:始终检查函数的返回值,处理错误情况
- 释放资源:确保所有分配的资源都被释放,如文件描述符、内存等
- 使用安全的函数:避免使用不安全的函数,如
gets、strcpy等 - 遵循函数的调用约定:正确传递参数,处理返回值
- 了解函数的限制:如缓冲区大小、参数范围等
- 使用适当的错误处理:如
perror、strerror等 - 测试边界情况:测试函数在边界情况下的行为
- 参考文档:查阅系统函数库的文档,了解函数的详细用法
12.2 性能优化
- 减少函数调用:对于频繁调用的函数,考虑内联或使用宏
- 缓存计算结果:对于计算密集型函数,缓存结果
- 使用适当的数据结构:选择高效的数据结构
- 避免不必要的转换:如字符串和数字之间的转换
- 使用编译器优化:如
-O2、-O3等优化选项
12.3 安全性
- 检查参数:验证所有函数参数的有效性
- 防止缓冲区溢出:使用安全的字符串处理函数
- 释放资源:确保所有分配的资源都被释放
- 避免使用不安全的函数:如
gets、strcpy等 - 使用地址随机化:编译时启用地址随机化
- 限制权限:最小化程序的权限
- 加密敏感数据:对敏感数据进行加密
- 防止注入攻击:如SQL注入、命令注入等
13. 系统函数库的跨平台兼容性
13.1 跨平台兼容性问题
- 头文件差异:不同平台的头文件可能不同
- 函数差异:不同平台的函数可能有不同的实现或行为
- 类型差异:不同平台的类型大小可能不同
- 系统调用差异:不同平台的系统调用可能不同
- 路径分隔符:不同平台的路径分隔符可能不同(
/ vs \)
13.2 解决方案
- 使用条件编译:根据不同平台使用不同的代码
- 使用宏定义:定义平台相关的宏
- 使用抽象层:为平台相关的功能创建抽象层
- 使用跨平台库:如SDL、Boost等
- 测试多个平台:确保代码在多个平台上都能正常工作
- 参考标准:遵循C语言标准,避免使用非标准功能
13.3 示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| #include <stdio.h>
#ifdef _WIN32 #include <windows.h> #define SLEEP(ms) Sleep(ms) #elif defined(__linux__) #include <unistd.h> #define SLEEP(ms) usleep((ms) * 1000) #elif defined(__APPLE__) #include <unistd.h> #define SLEEP(ms) usleep((ms) * 1000) #else #error Unsupported platform #endif
int main() { printf("Sleeping for 1 second...\n"); SLEEP(1000); printf("Woke up!\n"); return 0; }
|
14. 系统函数库的调试
14.1 调试工具
- gdb:GNU调试器
- valgrind:内存分析工具
- strace:系统调用跟踪工具
- ltrace:库函数调用跟踪工具
- gprof:性能分析工具
- addr2line:地址转换工具
14.2 调试技巧
- 使用
printf:在关键位置添加打印语句 - 使用
assert:在关键位置添加断言 - 检查返回值:始终检查函数的返回值
- 使用调试器:使用gdb等调试器逐步执行代码
- 使用内存分析工具:使用valgrind等工具检查内存问题
- 使用系统调用跟踪:使用strace等工具跟踪系统调用
- 查看核心转储:分析程序崩溃时生成的核心转储文件
- 使用日志:使用日志记录程序的执行情况
14.3 常见问题
14.3.1 段错误
原因:访问了无效的内存地址
解决:使用gdb或valgrind检查内存访问
14.3.2 内存泄漏
原因:分配的内存未被释放
解决:使用valgrind检查内存泄漏
14.3.3 文件操作错误
原因:文件不存在、权限不足等
解决:检查文件路径、权限,使用perror查看错误信息
14.3.4 网络连接错误
原因:网络不可达、端口未开放等
解决:检查网络连接、防火墙设置,使用perror查看错误信息
15. 示例代码
15.1 综合示例:文件复制程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| #include <stdio.h> #include <stdlib.h>
#define BUFFER_SIZE 4096
int main(int argc, char *argv[]) { FILE *src, *dest; char buffer[BUFFER_SIZE]; size_t n; if (argc != 3) { fprintf(stderr, "Usage: %s <source> <destination>\n", argv[0]); return 1; } src = fopen(argv[1], "rb"); if (src == NULL) { perror("fopen source"); return 1; } dest = fopen(argv[2], "wb"); if (dest == NULL) { perror("fopen destination"); fclose(src); return 1; } while ((n = fread(buffer, 1, BUFFER_SIZE, src)) > 0) { if (fwrite(buffer, 1, n, dest) != n) { perror("fwrite"); fclose(src); fclose(dest); return 1; } } if (ferror(src)) { perror("fread"); fclose(src); fclose(dest); return 1; } if (fclose(src) != 0) { perror("fclose source"); fclose(dest); return 1; } if (fclose(dest) != 0) { perror("fclose destination"); return 1; } printf("File copied successfully\n"); return 0; }
|
15.2 综合示例:简单的HTTP服务器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h>
#define PORT 8080 #define BUFFER_SIZE 4096
int main() { int server_fd, new_socket; struct sockaddr_in address; int opt = 1; int addrlen = sizeof(address); char buffer[BUFFER_SIZE] = {0}; char *response = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: 12\r\n\r\nHello World!"; if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { perror("socket failed"); exit(EXIT_FAILURE); } if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) { perror("setsockopt"); exit(EXIT_FAILURE); } address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons(PORT); if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) { perror("bind failed"); exit(EXIT_FAILURE); } if (listen(server_fd, 3) < 0) { perror("listen"); exit(EXIT_FAILURE); } printf("Server listening on port %d...\n", PORT); while (1) { if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) { perror("accept"); exit(EXIT_FAILURE); } read(new_socket, buffer, BUFFER_SIZE); printf("Request:\n%s\n", buffer); send(new_socket, response, strlen(response), 0); printf("Response sent\n"); close(new_socket); } return 0; }
|