首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C >> C 語言問答

C語言函數分類詳解:庫函數 vs 用戶自定義函數、標準庫核心模組與最佳實踐

     編輯:C 語言問答

標準分類:兩大類

構成 C 程式的函數劃分為兩類:
1. 庫函數 — 由實現提供,標頭文件聲明,鏈接時自動解析。
2. 用戶自定義函數 — 程式設計師編寫,滿足特定業務邏輯。

庫函數:標準庫核心模組速查表

C 標準庫 (ISO/IEC 9899) 按頭文件組織,現代開發建議優先使用 C 版頭文件 (`` 在 C++,C 直接用 ``)。

頭文件核心功能域常用函數/宏/型別示例
<stdio.h>輸入輸出 (流/檔案/標準流)`printf` `scanf` `fopen` `fclose` `fread` `fwrite` `fprintf` `fscanf` `fgets` `fputs` `getchar` `putchar` `sprintf` `sscanf` `perror` `tmpfile` `setvbuf` `FILE` `stdin` `stdout` `stderr`
<stdlib.h>通用工具 (記憶體/轉換/程式控制/排序查找/隨機數/環境)`malloc` `free` `realloc` `calloc` `aligned_alloc` `exit` `atexit` `abort` `system` `getenv` `atoi` `atol` `strtod` `strtol` `strtoul` `rand` `srand` `abs` `labs` `llabs` `div` `ldiv` `qsort` `bsearch` `NULL` `size_t` `RAND_MAX`
<string.h>字符串/記憶體操作`strlen` `strcpy` `strncpy` `strcat` `strncat` `strcmp` `strncmp` `strchr` `strrchr` `strstr` `strtok` `strerror` `memcpy` `memmove` `memcmp` `memset` `memchr`
<math.h>數學函數 (浮點/三角/指數/對數/冪/雙曲/分類/操作)`sin` `cos` `tan` `asin` `acos` `atan` `atan2` `exp` `log` `log10` `pow` `sqrt` `ceil` `floor` `fabs` `fmod` `hypot` `cbrt` `erf` `tgamma` `lgamma` `round` `trunc` `nearbyint` `FP_INFINITE` `FP_NAN` `FP_NORMAL` `FP_SUBNORMAL` `FP_ZERO` `INFINITY` `NAN` `M_PI` (常見擴展)
<ctype.h>字符分類/映射`isalpha` `isdigit` `isalnum` `isspace` `islower` `isupper` `isxdigit` `isprint` `iscntrl` `isgraph` `ispunct` `tolower` `toupper` (參數為 `int`,值為 `unsigned char` 或 `EOF`)
<stdint.h> (C99)精確寬度/最小寬度/最快/指針/最大整數型別`int8_t` `uint32_t` `int_least16_t` `int_fast32_t` `intptr_t` `uintptr_t` `intmax_t` `uintmax_t` `INT32_MIN` `UINT64_MAX` `PRId32` `PRIu64` (配合 ``)
<stdbool.h> (C99)布爾型別`bool` `_Bool` `true` `false` `__bool_true_false_are_defined`
<stddef.h>通用定義`size_t` `ptrdiff_t` `NULL` `offsetof` `max_align_t`
<time.h>日期時間`time` `clock` `difftime` `mktime` `localtime` `gmtime` `asctime` `ctime` `strftime` `struct tm` `clock_t` `time_t` `CLOCKS_PER_SEC` `timespec` (C11) `timespec_get`
<assert.h>斷言 (僅 Debug 生效)`assert(expr)` `NDEBUG` 宏控制
<errno.h>錯誤碼`errno` (執行緒局部) `EDOM` `ERANGE` `EILSEQ` `errno_t` (C11 附錄 K)
<setjmp.h>非局部跳轉`setjmp` `longjmp` `jmp_buf` (慎用,破壞 RAII/棧展開)
<signal.h>信號處理`signal` `raise` `SIGINT` `SIGTERM` `SIGSEGV` `SIGFPE` `SIGABRT` `SIG_DFL` `SIG_IGN` `SIG_ERR` `sig_atomic_t`
<locale.h>本地化`setlocale` `localeconv` `struct lconv` `LC_ALL` `LC_CTYPE` `LC_NUMERIC` `LC_TIME` `LC_COLLATE` `LC_MONETARY` `LC_MESSAGES`
<stdarg.h>可變參數`va_list` `va_start` `va_arg` `va_end` `va_copy` (C99)
<iso646.h> (C99)替代運算符拼寫`and` `or` `not` `bitand` `bitor` `xor` `compl` `and_eq` `or_eq` `xor_eq` `not_eq`
<wchar.h> / <wctype.h>寬字符/多位元組字符`wchar_t` `wint_t` `btowc` `wctob` `mbrtowc` `wcrtomb` `mbsrtowcs` `wcsrtombs` `wcscpy` `wcslen` `wprintf` `fwprintf` `iswalpha` `iswdigit` `towlower` `towupper`
<complex.h> (C99)複數數學`complex` `_Complex_I` `cabs` `carg` `cacos` `ccos` `cexp` `clog` `cpow` `csin` `csqrt` `creal` `cimag` `conj` `cproj`
<tgmath.h> (C99)類型泛型數學宏`sin` `cos` `exp` `log` `pow` `sqrt` `fabs` 等自動選擇 `float`/`double`/`long double`/`complex` 版本
<fenv.h> (C99)浮點環境`feclearexcept` `fegetexceptflag` `feraiseexcept` `fegetround` `fesetround` `fegetenv` `fesetenv` `feholdexcept` `feupdateenv` `FE_DIVBYZERO` `FE_INEXACT` `FE_INVALID` `FE_OVERFLOW` `FE_UNDERFLOW` `FE_ALL_EXCEPT` `FE_TONEAREST` `FE_DOWNWARD` `FE_UPWARD` `FE_TOWARDZERO`
<inttypes.h> (C99)整數格式轉換`PRId8` `PRIu64` `SCNd32` `SCNx16` `intmax_t` `uintmax_t` `imaxabs` `imaxdiv` `strtoimax` `strtoumax` `wcstoimax` `wcstoumax`
<stdalign.h> (C11)對齊控制`alignas` `alignof` `alignof` `max_align_t` `aligned_alloc`
<stdnoreturn.h> (C11)無返回函數屬性`noreturn` (C23 為關鍵字 `[[noreturn]]`)
<threads.h> (C11)執行緒 (可選實現)`thrd_t` `thrd_create` `thrd_join` `thrd_detach` `thrd_exit` `thrd_sleep` `mtx_t` `mtx_init` `mtx_lock` `mtx_unlock` `cnd_t` `cnd_init` `cnd_signal` `cnd_broadcast` `cnd_wait` `cnd_timedwait` `tss_t` `tss_create` `tss_set` `tss_get` `tss_delete` `call_once` `ONCE_FLAG_INIT`
<uchar.h> (C11)Unicode 工具`char16_t` `char32_t` `mbrtoc16` `c16rtomb` `mbrtoc32` `c32rtomb`

用戶自定義函數:設計最佳實踐

1. 單一職責原則 (SRP)

一個函數只做一件事,做好一件事。過長函數 (>50 行) 必須拆分。

2. 介面設計:參數與返回值


/* 良好介面範例 */
int read_config(const char *path, Config *out_cfg);  // 返回錯誤碼,輸出參數用指針
size_t str_copy(char *dst, size_t dst_sz, const char *src); // 返回寫入長度,防止溢出
void *aligned_alloc_custom(size_t alignment, size_t size); // 返回分配地址,失敗返回 NULL
  • 輸入參數:唯讀用 `const T *` / `const T`,大結構體傳指針。
  • 輸出參數:用 `T *out`,調用者分配記憶體,被調用者填充。
  • 輸入輸出參數:用 `T *inout`。
  • 返回值:狀態碼 (`int`/`enum`) 或計算結果 (非指針型別)。避免返回局部變量指針。
  • 錯誤處理:返回錯誤碼 + `errno` + 輸出參數 `NULL`,或結構體 `{int err; T value;}` (C11 `_Generic` 可模擬 Result 型別)。

3. 靜態內部函數


/* 文件內部輔助函數,不對外暴露 */
static void internal_cleanup(Context *ctx) { ... }
static int validate_input(const Input *in) { ... }

`static` 限制鏈接可見性,減少符號汙染,編譯器可更激進優化 (內聯/消除)。

4. 函數指針與回調


typedef int (*CompareFunc)(const void *a, const void *b);
void my_qsort(void *base, size_t nmemb, size_t size, CompareFunc cmp);

實現泛型演算法/事件驅動/插件架構的核心機制。

5. 遞歸與尾調用優化

  • 遞歸深度受棧大小限制 (通常 1-8MB),深度 > 1000 風險棧溢出。
  • 尾遞歸優化 (TCO) 依賴編譯器 (`-O2`/`-O3` GCC/Clang 常支援,MSVC 不保證)。
  • 深度不確定/較大場景改寫為迭代 (顯式棧/循環)。

命名規範建議

類別風格例子
庫函數 (標準)小寫 + 下劃線`memcpy` `strtoul` `qsort`
用戶函數 (專案統一)小寫 + 下劃線 (snake_case) 推薦`parse_config` `calculate_crc32` `http_request_send`
模組前綴 (避免衝突)`module_action``json_parse` `net_connect` `db_query`
布爾查詢`is_` `has_` `can_` `should_``is_valid` `has_permission` `can_allocate`
轉換/獲取`to_` `from_` `get_` `make_` `create_` `destroy_``to_upper` `get_user_by_id` `create_context`

總結

  • 庫函數:站在巨人肩膀上,熟練掌握 `` `` `` `` `` `` `` `` 核心模組,不要重複造輪子 (除非教學/極致優化/特殊約束)。
  • 自定義函數:遵循 SRP、介面契約 (const/輸出參數/錯誤碼)、靜態封裝、模組前綴命名、文件級文檔註釋 (Doxygen/GTK-Doc 格式)。
  • 現代 C 專案結構:`src/` (實現) + `include/` (公共頭文件) + `tests/` + `CMakeLists.txt` + `.clang-format` + `.github/workflows/ci.yml`。函數是模組化的原子單元,設計好函數介面,架構自然清晰。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved