当前位置:网站首页>C語言最佳實踐之庫文件介紹(下)
C語言最佳實踐之庫文件介紹(下)
2022-06-10 11:47:00 【徐福記456】
C語言的庫文件包括:pthread線程、assert斷言、string字符串、time時間、math數學運算、std開頭的標准庫、sys開頭的系統庫等。其中,標准庫有stdalign.h、stdarg.h、stdatomic.h、stdbool.h、stddef.h、stdint.h、stdio.h、stdlib.h。系統庫有sys/mman.h、sys/stat.h、sys/ioctl.h、sys/file.h。本篇文章主要介紹std標准庫和sys系統庫。
上一篇C語言庫文件的介紹可查看:C語言最佳實踐之庫文件介紹(上)
目錄
一、stddef.h預先宏定義
1、offsetof
stddef提供offsetof、size_t、ptrdiff等宏定義。其中offsetof用於獲取成員變量在結構體的偏移比特置。offsetof(t, d)的示例代碼如下:
struct Programmer {
int age;
char* name;
char* post;
};
void print_offset() {
printf("offset of struct =%lu", offsetof(struct Programmer, name));
}2、ptrdiff_t
ptrdiff_t用於計算兩個指針相减的差值。比如一個指針指向字符串的頭,另一個指針指向字符串的尾,那麼兩個指針的差值等於字符串長度。示例代碼如下:
char* str = "hello, world!";
char* ptr_start = str;
char* ptr_end = str + strlen(str);
ptrdiff_t diff = ptr_end - ptr_start;
printf("ptr diff=%td\n", diff);3、__func__與__LINE__
在調試時,我們需要打印哪個文件、哪個函數、哪一行有問題,__FILE__、__func__、__LINE__就派上用場了。如果要獲取當前格式化時間戳,可以用__TIMESTAMP__。這些宏定義都是以雙下劃線開頭。示例代碼如下:
printf("func=%s\n", __func__);
printf("file=%s\n", __FILE__);
printf("line=%d\n", __LINE__);
printf("timestamp=%s\n", __TIMESTAMP__);對應的打印輸出如下:
func=macro_define
file=/Users/frank/Documents/FFmpegAndroid/app/src/main/cpp/test_api.c
line=357
timestamp=Sat Jun 4 17:19:22 2022二、stdio.h
stdio.h提供文件的常用操作,包括:打開、讀寫、關閉、重命名、删除、刷新、標准輸出等等。具體介紹如下錶所示:
| 函數 | 描述 |
| FILE* fopen(const char* filename, const char* mode) | 打開文件,mode包括:只讀、只寫、讀寫、追加等 |
| size_t fread(void* ptr, size_t size, size_t count, FILE* stream) | 讀取文件,讀取指定大小的內容到緩沖區 |
| size_t fwrite(const void* ptr, size_t size, size_t count, FILE* stream) | 寫入文件,如果是讀寫模式會覆蓋原始內容,追加是從末尾開始寫 |
| int fseek(FILE* stream, long offset, int whence) | 移動文件指針,seek模式:SEEK_SET、SEEK_CUR\SEEK_END |
| long ftell(FILE* stream) | 獲取當前比特置,結合fseek使用 |
| int fflush(FILE* stream) | 刷新文件緩沖區 |
| void rewind(FILE* stream) | 重置文件指針到文件開頭 |
| int remove(const char* filename) | 删除文件,返回成功或失敗 |
| int rename(const char* old, const char* new) | 重命名文件 |
| int fclose(FILE* stream) | 關閉文件 |
| int printf(const char* format, ...) | 打印輸出到控制臺 |
| int scanf(const char* format, ...) | 讀入內容 |
| int sprintf(char* s, const char* format, ...) | 輸出到字符串 |
| int fprintf(FILE* stream, const char* format, ...) | 輸出到文件 |
| int vprintf(const char* format, va_list arg) | 輸出到可變參數列錶 |
int getc(FILE* stream) | 從文件獲取一個字符 |
| int putc(int c, FILE* stream) | 寫入一個字符到文件 |
| int feof(FILE* stream) | 判斷文件是否到末尾,eof=-1 |
| int ferror(FILE* stream) | 獲取文件錯誤碼 |
| void clearerr(FILE* stream) | 清除异常信息 |
| void perror(const char* s) | 錯誤描述信息輸出到標准錯誤 |
| void setbuf(FILE* stream, char* buf) | 設置文件緩沖區 |
1、打開文件
char* path = "sdcard/hello.txt";
FILE* file = fopen(path, "wb+");2、讀寫數據
char *buf0 = "Just do it";
size_t size = strlen(buf0);
fwrite(buf0, size, 1, file); // 寫文件
fseek(file, 0, SEEK_SET);
char *buf1 = (char*) malloc(size * sizeof(char));
fread(buf1, size * sizeof(char), 1, file); // 讀文件3、移動文件指針
fseek(file, 10, SEEK_SET);4、獲取文件長度
fseek(file, 0, SEEK_END);
long len = ftell(file);5、重命名文件
rename("sdcard/2.txt", "sdcard/222.txt");6、判斷是否到末尾
int ret = feof(file);7、重置文件到開頭比特置
rewind(file);9、删除文件
remove("sdcard/1.txt");10、關閉文件
fclose(file);三、stdlib.h
stdlib.h提供內存分配與釋放、隨機數的生成、進程退出、執行命令行、字符串轉數值類型、二分查找算法、快排算法、求絕對值等操作。其中內存分配包括:malloc、calloc、realloc、aligned_alloc。具體對比如下錶所示:
| malloc | 內存分配,默認內存對齊 |
| calloc | 內存分配,並且初始化 |
| realloc | 重新分配,拷貝舊內存到新區域 |
| aligned_alloc | 對齊分配,指定對齊單比特大小 |
stdlib相關的函數如下:
void lib_api() {
// 內存分配
void* malloc(size_t size);
// 重新分配內存,拷貝舊內存到新內存空間,釋放舊內存
void* realloc(void* ptr, size_t size);
// 內存對齊分配
void *aligned_alloc(size_t alignment, size_t size);
// 內存分配並且初始化,相當於malloc + memset
void* calloc(size_t nmemb, size_t size);
// 釋放內存
void free(void* ptr);
// 异常的進程終止
void abort(void);
// 注册終止函數,在exit退出時調用
int atexit(void (*func)(void));
// status=0為正常退出,status!=0為异常退出
void exit(int status);
// 字符串轉數值類型
double atof (const char* nptr);
int atoi (const char* nptr);
long atol (const char* nptr);
// 執行命令行,system在原進程開辟新的進程,exec用新進程覆蓋原進程
int system(const char* string);
// 二分法查找
void* bsearch(const void* key, const void* base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
// 快排算法
void qsort(void* base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
// 求絕對值
int abs(int j);
// 生成隨機數
int rand(void);
void srand(unsigned int seed);
long random();
}四、string.h
string.h提供字符串的常見操作:拷貝、比較、拼接、查找、分割。其中,部分的mem操作和str操作功能一樣。比如,memcpy拷貝內存,可以拷貝結構體、類、數組等,但需要指定長度;strcpy拷貝字符串,僅限於字符串,不需要指定長度。兩者對比如下:
void* memcpy(void* dest, const void* src, size_t n) 拷貝內存,包括結構體、類、數組等 | char* strcpy (char* dest, const char* src) 拷貝字符串 |
int memcmp(const void* str1, const void* str2, size_t n) 內存值比較 | int strcmp (const char* str1, const char* str2) 字符串比較 |
void* memchr(const void* str, int c, size_t n) 內存區域查找字符 | char* strchr(const char* str, int c) 字符串中查找字符 |
其他的常用函數如下:
void string_api() {
// 移動指定長度的源內存到目的內存
void* memmove(void* dest, const void* src, size_t n);
// 設置內存值,用於內存初始化
void* memset(void* str, int c, size_t n);
// 拼接字符串
char* strcat (char* dest, const char* src);
// 查找字符在字符串最後一次出現的比特置
char* strrchr(const char* str, int c);
// 查找str2在str1字符串出現的比特置
char* strstr(const char* str1, const char* str2);
// 分割字符串
char* strtok(char* src, const char* delim);
// 把錯誤碼轉換為字符串
char* strerror(int errnum);
// 獲取字符串長度
size_t strlen(const char* s);
}五、stdatomic.h
1、原子類型
stdatomic.h提供原子操作,線程安全,比鎖更加輕量級。支持的原子類型包括:bool、char、int、short、long等。宏定義如下(包括但不限於):
typedef _Atomic(bool) atomic_bool;
typedef _Atomic(char) atomic_char;
typedef _Atomic(short) atomic_short;
typedef _Atomic(int) atomic_int;
typedef _Atomic(long) atomic_long;2、原子初始化
使用atomic_init()進行初始化,需要注意,第一個參數是對象的地址,代碼如下:
atomic_int count;
atomic_init(&count, 1);3、原子讀寫
使用atomic_load()進行讀取,atomic_store_explicit()進行寫入,代碼如下:
// 讀取
atomic_load(&count);
// 寫入
atomic_store_explicit(&count, 3, memory_order_seq_cst);4、原子加减
原子運算支持加、减、或、异或、與。以加减運算為例:
atomic_fetch_add(&count, 5);
atomic_fetch_sub(&count, 3);5、原子交換
原子交換步驟分為三步:讀取、比較、寫入。代碼如下:
atomic_exchange(&count, 6);6、內存屏障
原子操作提供fence內存屏障,與關鍵字volatile類似,保證內存有序性。有一個memory_order枚舉類型,包括獲取操作、釋放操作、獲取與釋放、消費操作、無序性、有序性等,具體如下:
typedef enum {
memory_order_relaxed = __ATOMIC_RELAXED,
memory_order_consume = __ATOMIC_CONSUME,
memory_order_acquire = __ATOMIC_ACQUIRE,
memory_order_release = __ATOMIC_RELEASE,
memory_order_acq_rel = __ATOMIC_ACQ_REL,
memory_order_seq_cst = __ATOMIC_SEQ_CST
} memory_order;對應的函數API如下:
atomic_thread_fence(memory_order order);六、stdarg.h
stdarg.h提供可變參數的遍曆,由va_start()、va_arg()和va_end()三個函數組成,還有一個va_list可變參數列錶。其中va_start()是參數列錶的開始,va_arg()是獲取列錶的下一個,va_end()結束遍曆釋放內存。示例代碼如下:
void sum_args(int args, ...) {
int sum = 0;
va_list ap;
va_start(ap, args);
for (int i=0; i<args; i++) {
sum += va_arg(ap, int);
}
va_end(ap);
printf("sum=%d\n", sum);
}大家可以猜猜這個函數調用的結果:
sum_args(3, 11, 22, 33);七、sys/mmap.h
mmap.h提供內存映射的函數,相關函數聲明如下:
/**
* [mmap](http://man7.org/linux/man-pages/man2/mmap.2.html)
* creates a memory mapping for the given range.
*
* Returns the address of the mapping on success,
* and returns `MAP_FAILED` and sets `errno` on failure.
*/
void* mmap(void* addr, size_t size, int prot, int flags, int fd, off_t offset);
/**
* [munmap](http://man7.org/linux/man-pages/man2/munmap.2.html)
* deletes a memory mapping for the given range.
*
* Returns 0 on success, and returns -1 and sets `errno` on failure.
*/
int munmap(void* addr, size_t size);mmap()函數的第四個參數prot類型包括:讀、寫、執行、無權限。如下圖所示:

第五個參數flag標志比特包括:共享的、私有的、固定的。如下圖所示:
內存映射的示例代碼如下:
void mapping() {
char *buf = "hello, world";
// file:use data in buf
int fd = open("sdcard/hello.txt", O_RDWR);
write(fd, buf, strlen(buf));
// mapping:use data at address
fd = open("sdcard/hello.txt", O_RDWR);
void* address = mmap(0, strlen(buf), PROT_READ, MAP_PRIVATE, fd, 0);
}八、sys/stat.h
1、stat結構體
stat.h用於獲取文件狀態信息,包括:設備id、文件大小、文件訪問權限、文件修改時間、文件訪問時間、序列號、文件鏈接的數量等。stat結構體如下:
struct stats {
dev_t st_dev; // ID of device containing file
ino_t st_ino; // file serial number
mode_t st_mode; // mode of file
nlink_t st_nlink; // number of links to the file
uid_t st_uid; // user ID of file
gid_t st_gid; // group ID of file
dev_t st_rdev; // device ID
off_t st_size; // file size in bytes
int st_blksize; // a filesystem-specific preferred I/O block size
long st_blocks; // number of blocks allocated for this object
struct timespec st_atim; // time of last access
struct timespec st_mtim; // time of last data modification
struct timespec st_ctim; // time of last status change
};2、統計文件信息
stat()函數的使用示例如下:
void file_stat() {
struct stat buf;
const char* path = "sdcard/hello.txt";
stat(path, &buf);
printf("file mode:%u\n",buf.st_mode); // 文件訪問權限
printf("file size:%lu\n",buf.st_size); // 文件大小
printf("file access time:%lu\n",buf.st_atime); // 文件訪問時間
printf("file modify time:%lu\n",buf.st_mtime); // 文件修改時間
}九、signal.h
1、信號分類
signal.h是系統提供的信號,包括:非法指令、函數陷阱、异常終止、非法地址、殺掉進程、內存异常、進程退出、浮點异常等。比如,訪問一個空指針,或者已經釋放的指針,或者訪問指針指向的內存區域超出邊界,系統會發送SIGSEGV信號。再比如,使用命令行殺掉進程kill -9 pid,系統會發生SIGKILL信號。具體信號與數值如下錶所示:
| 信號 | 描述 | 信號 | 描述 |
| SIGHUP 1 | 信號掛起 | SIGCHLD 17 | 子進程結束 |
| SIGINT 2 | 信號中斷 | SIGCONT 18 | 進程恢複 |
| SIGQUIT 3 | 進程退出 | SIGSTOP 19 | 程序停止 |
| SIGILL 4 | 非法指令 | SIGTSTP 20 | 停止進程 |
| SIGTRAP 5 | 函數陷阱 | SIGTTIN 21 | 讀取數據 |
| SIGABRT 6 | 异常終止 | SIGTTOU 22 | 寫入數據 |
| SIGBUS 7 | 非法地址 | SIGURG 23 | 緊急處理 |
| SIGFPE 8 | 浮點溢出 | SIGXCPU 24 | 超出CPU限制 |
| SIGKILL 9 | 殺掉進程 | SIGXFSZ 25 | 擴大文件 |
| SIGUSR1 10 | 用戶保留 | SIGVTALRM 26 | 虛擬時鐘 |
| SIGSEGV 11 | 內存异常 | SIGPROF 27 | CPU時鐘 |
| SIGUSR2 12 | 用戶保留 | SIGWINCH 28 | 窗口變化 |
| SIGPIPE 13 | 信號管道 | SIGIO 29 | 文件描述符就緒 |
| SIGALRM 14 | 定時時鐘 | SIGPWR 30 | 電源异常 |
| SIGTERM 15 | 程序結束 | SIGSYS 31 | 非法系統調用 |
| SIGSTKFLT 16 | 處理器棧异常 | SIGRTMIN 32 | 實時信號 |
2、信號捕獲
信號處理函數包括:信號捕獲、中斷、等待、掛起、生成信號、殺掉進程。具體如下:
int sigaction(int signal, struct sigaction* new_action, struct sigaction* old_action); // 捕獲信號
int siginterrupt(int signal, int flag); // 信號中斷
int sigwait(const sigset_t* set, int* signal); // 信號等待
int sigsuspend(const sigset_t* mask); // 信號掛起
int raise(int signal); // 發送信號
int kill(pid_t pid, int signal); // 殺掉進程下面我們來模擬發送信號與捕獲信號的過程:
void process_signal() {
printf("receive sig=%d\n", SIGFPE);
}
void test_signal() {
struct sigaction action;
action.sa_handler = process_signal; // 聲明信號處理函數
sigaction(SIGFPE, &action, NULL); // 捕獲信號
raise(SIGFPE); // 發送信號
}边栏推荐
- [PaperNote] Confidential Computing Direction
- mysql8.0安装
- 【论文泛读】 知识蒸馏:Distilling the knowledge in a neural network
- 【万人独木桥】那个夏天—后高考生活该如何安排?
- Do you have an online stock account? Is it safe to open an account online?
- 证券期货业迎数据监管新规,IP-guard助力完善数据安全管理
- “减负”,让“猪”可以飞得更高
- Pytorch tensor高阶操作
- 多线程杀手锏---countDownLatch&&CyclicBarrier
- 如何编写产品营销策划方案
猜你喜欢

Transfomer components and pytoch

IndexedDB 数据库的使用

国际档案日|瀚高数据库以科技赋能数字档案建设

2022 CISCN 初赛pwn完整wp

【网易云信】深度剖析「圈组」消息系统设计 | 「圈组」技术系列文章

How can the team be dissolved...

线性代数的本质6 逆矩阵、列空间与零空间

Transfomer components and pytoch

【雲圖說】每個成功的業務系統都離不開APIG的保駕護航

La poignée d'enseignement de la station B vous apprend à utiliser le masque yolov5 pour tester les éléments de l'enregistrement le plus complet (apprentissage profond / détection d'objets / pythorch)
随机推荐
正常的controller结构
Surrender firehouse database access: Twitter is ready to meet Musk's requirements
Dell G7 computer shutdown keypad
有在网上股票开户的吗?股票网上开户安全吗?
还活在上个时代,Etcd 3.0 实现分布式锁竟如此简单!
Opérations de haut niveau du capteur de pythorch
Do not concatenate text displayed with setText,use resource string with placeholders.
dell G7 电脑关闭小键盘
Massive data: the first stock of Huawei Gauss database (depth)
时间轴、物流信息。你根本不需要StepView
线性代数的本质6 逆矩阵、列空间与零空间
多线程杀手锏---countDownLatch&&CyclicBarrier
JS implements tree data operation through recursion
360, Tsinghua | zero and R2D2: a large-scale Chinese cross modal benchmark and visual language Framework
Flutter库推荐Sizer 可帮助您轻松创建响应式 UI
[WIP] Openstack Masakari (by quqi99)
Flutter websocket example
安全工器具的使用和检查
从“化学家”到开发者,从甲骨文到TDengine,我人生的两次重要抉择
【Question】what‘s the scenario of aliasing a class interface