-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
493 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,127 @@ | ||
# 文件操作 | ||
|
||
## `FILE` 结构体 | ||
|
||
C 语言标准未指定 `FILE` 结构体的具体实现,甚至没有说明它是不是完整类型。`FILE` 对象可能在语义上不可复制。 | ||
|
||
## 文件访问 | ||
|
||
## 直接输入输出 | ||
在 C 语言中,文件操作主要通过 `stdio.h` 头文件中定义的函数来实现。最常用的文件操作函数包括: | ||
|
||
### 打开文件 | ||
|
||
```c | ||
FILE* fopen(const char* filename, const char* mode); | ||
``` | ||
常用的模式有: | ||
| 文件访问模式字符串 | 含义 | 解释 | 若文件已存在的动作 | 若文件不存在的动作 | | ||
| :----------------: | :--: | :--: | :----------------: | :----------------: | | ||
| `"r"` | 读 | 打开文件以读取 | 从头读 | 打开失败 | | ||
| `"w"` | 写 | 创建文件以写入 | 销毁内容 | 创建新文件 | | ||
| `"a"` | 附加 | 附加到文件 | 写到结尾 | 创建新文件 | | ||
字符串的其余部分可以包含以下任意顺序的字符,并进一步影响文件的打开方式: | ||
- `"b"` :以二进制模式打开文件。 | ||
- `"x"` :以独占模式打开文件。 | ||
- `"p"` :以私有模式打开文件。 | ||
- `"+"` :以更新模式打开文件(可读可写)。 | ||
### 关闭文件 | ||
```c | ||
int fclose(FILE* stream); | ||
``` | ||
|
||
### 直接输入输出 | ||
|
||
#### 字符操作 | ||
|
||
```c | ||
int fputc(int char, FILE* stream); // 写入单个字符 | ||
int fgetc(FILE* stream); // 读取单个字符 | ||
``` | ||
### 字符串操作 | ||
```c | ||
int fputs(const char* str, FILE* stream); // 写入字符串 | ||
char* fgets(char* str, int n, FILE* stream); // 读取字符串 | ||
``` | ||
|
||
### 格式化输入输出 | ||
|
||
```c | ||
int fprintf(FILE* stream, const char* format, ...); // 格式化写入 | ||
int fscanf(FILE* stream, const char* format, ...); // 格式化读取 | ||
``` | ||
## 文件定位 | ||
### 获取当前位置 | ||
```c | ||
long ftell(FILE* stream); | ||
``` | ||
|
||
### 设置位置 | ||
|
||
```c | ||
int fseek(FILE* stream, long offset, int whence); | ||
``` | ||
定位参数: | ||
- `SEEK_SET`: 文件开头 | ||
- `SEEK_CUR`: 当前位置 | ||
- `SEEK_END`: 文件末尾 | ||
### 重置位置 | ||
```c | ||
void rewind(FILE* stream); // 将位置重置到文件开头 | ||
``` | ||
|
||
## 对文件的操作 | ||
|
||
### 文件重命名 | ||
|
||
```c | ||
int rename(const char* oldname, const char* newname); | ||
``` | ||
### 删除文件 | ||
```c | ||
int remove(const char* filename); | ||
``` | ||
|
||
### 示例代码 | ||
|
||
```c | ||
#include <stdio.h> | ||
|
||
int main() { | ||
FILE* fp; | ||
char buffer[100]; | ||
|
||
// 写入文件 | ||
fp = fopen("test.txt", "w"); | ||
if (fp != NULL) { | ||
fprintf(fp, "Hello, File!\n"); | ||
fclose(fp); | ||
} | ||
|
||
// 读取文件 | ||
fp = fopen("test.txt", "r"); | ||
if (fp != NULL) { | ||
fgets(buffer, 100, fp); | ||
printf("读取的内容:%s", buffer); | ||
fclose(fp); | ||
} | ||
|
||
return 0; | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,193 @@ | ||
# 线程 | ||
|
||
C11 标准引入了线程支持库(`<threads.h>`),提供了标准的多线程编程接口。 | ||
|
||
## threads.h | ||
|
||
### 线程类型和函数 | ||
|
||
主要类型: | ||
|
||
- `thrd_t`: 线程标识符 | ||
- `mtx_t`: 互斥锁 | ||
- `cnd_t`: 条件变量 | ||
- `tss_t`: 线程局部存储 | ||
- `once_flag`: 一次性初始化标记 | ||
|
||
主要函数: | ||
|
||
- `thrd_create()`: 创建线程 | ||
- `thrd_join()`: 等待线程结束 | ||
- `mtx_init()`: 初始化互斥锁 | ||
- `mtx_lock()`: 锁定互斥锁 | ||
- `mtx_unlock()`: 解锁互斥锁 | ||
- `cnd_signal()`: 发送信号 | ||
- `cnd_wait()`: 等待条件变量 | ||
- `tss_set()`: 设置线程局部存储 | ||
- `tss_get()`: 获取线程局部存储 | ||
- `tss_delete()`: 删除线程局部存储 | ||
|
||
### 创建线程 | ||
|
||
使用 `thrd_create` 函数创建新线程: | ||
|
||
```c | ||
#include <threads.h> | ||
#include <stdio.h> | ||
|
||
int thread_func(void* arg) { | ||
printf("线程运行中...\n"); | ||
return 0; | ||
} | ||
int main(void) { | ||
thrd_t thr; | ||
int result = thrd_create(&thr, thread_func, NULL); | ||
if (result != thrd_success) { | ||
printf("创建线程失败\n"); | ||
return 1; | ||
} | ||
// 等待线程结束 | ||
thrd_join(thr, NULL); | ||
return 0; | ||
} | ||
``` | ||
### 互斥锁 | ||
保护共享资源: | ||
```c | ||
#include <threads.h> | ||
mtx_t mutex; | ||
int shared_data = 0; | ||
int main(void) { | ||
// 初始化互斥锁 | ||
if (mtx_init(&mutex, mtx_plain) != thrd_success) { | ||
return 1; | ||
} | ||
// 使用互斥锁 | ||
mtx_lock(&mutex); | ||
shared_data++; // 临界区 | ||
mtx_unlock(&mutex); | ||
// 销毁互斥锁 | ||
mtx_destroy(&mutex); | ||
return 0; | ||
} | ||
``` | ||
|
||
### 条件变量 | ||
|
||
用于线程同步: | ||
|
||
```c | ||
#include <threads.h> | ||
|
||
mtx_t mutex; | ||
cnd_t cond; | ||
int ready = 0; | ||
|
||
int producer(void* arg) { | ||
mtx_lock(&mutex); | ||
ready = 1; | ||
cnd_signal(&cond); | ||
mtx_unlock(&mutex); | ||
return 0; | ||
} | ||
|
||
int consumer(void* arg) { | ||
mtx_lock(&mutex); | ||
while (!ready) { | ||
cnd_wait(&cond, &mutex); | ||
} | ||
mtx_unlock(&mutex); | ||
return 0; | ||
} | ||
``` | ||
### 线程局部存储 | ||
每个线程独有的存储空间: | ||
```c | ||
#include <threads.h> | ||
tss_t key; | ||
void destructor(void* data) { | ||
free(data); | ||
} | ||
int thread_func(void* arg) { | ||
int* value = malloc(sizeof(int)); | ||
*value = 42; | ||
// 设置线程局部存储 | ||
tss_set(key, value); | ||
// 获取线程局部存储 | ||
int* stored = tss_get(key); | ||
printf("值: %d\n", *stored); | ||
return 0; | ||
} | ||
int main(void) { | ||
// 创建线程局部存储键 | ||
if (tss_create(&key, destructor) != thrd_success) { | ||
return 1; | ||
} | ||
// ... 创建线程等操作 ... | ||
tss_delete(key); | ||
return 0; | ||
} | ||
``` | ||
|
||
### 一次性初始化 | ||
|
||
确保初始化代码只执行一次: | ||
|
||
```c | ||
#include <threads.h> | ||
|
||
once_flag flag = ONCE_FLAG_INIT; | ||
|
||
void init_function(void) { | ||
// 只执行一次的初始化代码 | ||
printf("初始化...\n"); | ||
} | ||
|
||
int thread_func(void* arg) { | ||
call_once(&flag, init_function); | ||
return 0; | ||
} | ||
``` | ||
## 返回值和错误处理 | ||
线程函数的返回值: | ||
- `thrd_success`: 成功 | ||
- `thrd_error`: 一般错误 | ||
- `thrd_nomem`: 内存不足 | ||
- `thrd_timedout`: 超时 | ||
- `thrd_busy`: 资源忙 | ||
## 其他重要函数 | ||
- `thrd_current()`: 获取当前线程标识符 | ||
- `thrd_equal()`: 比较两个线程标识符 | ||
- `thrd_sleep()`: 线程休眠 | ||
- `thrd_yield()`: 让出 CPU 时间片 | ||
## 注意事项 | ||
1. 检查编译器支持,注意是否需要特殊编译选项 | ||
2. 检查返回值,进行错误处理 | ||
3. 注意资源的正确释放 | ||
4. 避免死锁 |
Oops, something went wrong.