文件狀態獲取:stat 族函數
函數原型
#include
#include
int stat(const char *pathname, struct stat *statbuf);
int lstat(const char *pathname, struct stat *statbuf); // 不跟隨符號鏈接
int fstat(int fd, struct stat *statbuf); // 基於文件描述符
關鍵結構體成員 (struct stat)
| 成員 | 含義 | 常用宏/判斷 |
| st_mode | 文件類型與權限 | S_ISREG() S_ISDIR() S_ISLNK() S_IRUSR 等 |
| st_ino | inode 號 | 硬鏈接同 inode |
| st_dev | 設備號 | 跨設備判斷 |
| st_nlink | 硬鏈接數 | >1 表示有硬鏈接 |
| st_uid / st_gid | 所有者用戶/組 ID | 權限檢查 |
| st_size | 文件大小 (字節) | 常規文件有效 |
| st_atime / st_mtime / st_ctime | 最後訪問/修改/狀態變更時間 | time_t 類型 |
| st_blksize / st_blocks | 塊大小/佔用塊數 | 磁盤佔用估算 |
實戰模板:安全獲取文件大小
long long get_file_size(const char *path) {
struct stat st;
if (stat(path, &st) == -1) return -1; // errno 已設置
if (!S_ISREG(st.st_mode)) return -2; // 非常規文件
return (long long)st.st_size;
}
內存填充:memset 深度解析
原型與語義
#include
void *memset(void *s, int c, size_t n);
- 將
s 起始的 n 個字節**全部**設置為 (unsigned char)c。
- 返回
s。
- 只能按字節填充,不可直接用於 int/float 數組初始化非 0/-1 值。
正確用法示例
// 1. 結構體/數組歸零 (最常用)
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
// 2. 字符填充
char buf[100];
memset(buf, 'A', sizeof(buf)); // 全 'A'
// 3. 指針數組置 NULL (行為未定義! 標準不保證 NULL 全 0 位模式)
// 錯誤: memset(ptr_arr, 0, sizeof(ptr_arr));
// 正確: for (i=0; i
常見陷阱
- 參數順序:
memset(dst, val, size),別寫反。
- 類型懲罰:對非字符類型填充非 0/-1 導致不可移植行為。
- 重疊內存:
memset 不處理重疊,源目重疊行為未定義 (用 memmove 處理重疊拷貝)。
- 優化消除:釋放前清零敏感數據用
explicit_bzero / memset_s (C11) 防止編譯器優化掉。
隨機數生成:rand / srand / RAND_MAX
基礎 API
#include
int rand(void); // 返回 0 ~ RAND_MAX
void srand(unsigned seed); // 設置種子
#define RAND_MAX 32767 // 至少 32767 (15 位)
現代最佳實踐:拒絕 rand(),用 (C++) 或 OS 熵源 (C)
| 場景 | 推薦方案 | 原因 |
| C 一般用途 | random() / srandom() (BSD 擴展) | 周期長、質量優於 rand |
| C 加密級 | getrandom() (Linux 3.17+) / /dev/urandom | 密碼學安全 |
| C++11+ | std::mt19937 + std::uniform_int_distribution | 標準庫、高質量、類型安全 |
| 跨平台 C | PCG / xoshiro256** 等無狀態生成器 | 單頭文件、極快、統計學優良 |
若必須用 rand():正確區間映射
// [0, n-1] 均勻分佈 (拒絕採樣消除模偏)
int rand_range(int n) {
if (n <= 0) return 0;
int limit = RAND_MAX - (RAND_MAX % n);
int r;
do { r = rand(); } while (r >= limit);
return r % n;
}
// [min, max] 閉區間
int rand_int(int min, int max) {
return min + rand_range(max - min + 1);
}
// 雙精度浮點 [0.0, 1.0)
double rand_double(void) {
return (double)rand() / (RAND_MAX + 1.0);
}
綜合實戰:文件隨機讀取片段
#include
#include
#include
#include
#include
#include
void print_random_chunk(const char *path, size_t chunk_sz) {
struct stat st;
if (stat(path, &st) || !S_ISREG(st.st_mode)) return;
if (st.st_size < chunk_sz) chunk_sz = st.st_size;
int fd = open(path, O_RDONLY);
if (fd < 0) return;
off_t max_off = st.st_size - chunk_sz;
off_t off = (off_t)((double)random() / (RAND_MAX + 1.0) * (max_off + 1));
lseek(fd, off, SEEK_SET);
char *buf = malloc(chunk_sz);
if (buf) {
read(fd, buf, chunk_sz);
fwrite(buf, 1, chunk_sz, stdout);
free(buf);
}
close(fd);
}
總結速查卡
| 函數 | 頭文件 | 核心用途 | 關鍵注意點 |
| stat/lstat/fstat | sys/stat.h | 文件元信息 | 檢查返回值,用宏判斷類型,st_size 可能超過 32 位 |
| memset | string.h | 字節級填充 | 只填 0/-1 安全,指針/浮點/結構體非零填充不可移植 |
| rand/srand | stdlib.h | 偽隨機數 | 質量差、有模偏、非線程安全、勿用於安全場景 |
| random/srandom | stdlib.h | 更好偽隨機 | BSD 擴展,Linux/Unix 通用 |
| getrandom | sys/random.h | 加密安全隨機 | Linux 3.17+,阻塞行為可控 |