perlclib - 標準 C 函式庫函式的內部替換
Perl 移植者應注意的一件事是,perl 本身並不會使用太多 C 標準函式庫;例如,您會看到幾乎沒有使用 ctype.h 函式。這是因為 Perl 傾向於重新實作或抽象標準函式庫函式,以便我們確切知道它們將如何運作。
這是一份參考卡,提供給熟悉 C 函式庫且想要以 Perl 方式執行作業的人員;告訴他們應該使用哪些函式,而不是更常見的 C 函式。
在以下表格中
sv
、av
、hv
等表示其各自類型的變數。
您應該使用 Perl 抽象層,而不是 stdio.h 函式。您需要處理 PerlIO*
類型,而不是 FILE*
類型。別忘了,使用新的 PerlIO 分層 I/O 抽象時,FILE*
類型甚至可能不可用。另請參閱 perlapio
文件,以取得有關以下函式的更多資訊
Instead Of: Use:
stdin PerlIO_stdin()
stdout PerlIO_stdout()
stderr PerlIO_stderr()
fopen(fn, mode) PerlIO_open(fn, mode)
freopen(fn, mode, stream) PerlIO_reopen(fn, mode, perlio) (Dep-
recated)
fflush(stream) PerlIO_flush(perlio)
fclose(stream) PerlIO_close(perlio)
Instead Of: Use:
fprintf(stream, fmt, ...) PerlIO_printf(perlio, fmt, ...)
[f]getc(stream) PerlIO_getc(perlio)
[f]putc(stream, n) PerlIO_putc(perlio, n)
ungetc(n, stream) PerlIO_ungetc(perlio, n)
請注意,fread
和 fwrite
的 PerlIO 等效項與其 C 函式庫對應項略有不同
fread(p, size, n, stream) PerlIO_read(perlio, buf, numbytes)
fwrite(p, size, n, stream) PerlIO_write(perlio, buf, numbytes)
fputs(s, stream) PerlIO_puts(perlio, s)
沒有等效於 fgets
的函式;應該改用 sv_gets
fgets(s, n, stream) sv_gets(sv, perlio, append)
Instead Of: Use:
feof(stream) PerlIO_eof(perlio)
fseek(stream, n, whence) PerlIO_seek(perlio, n, whence)
rewind(stream) PerlIO_rewind(perlio)
fgetpos(stream, p) PerlIO_getpos(perlio, sv)
fsetpos(stream, p) PerlIO_setpos(perlio, sv)
ferror(stream) PerlIO_error(perlio)
clearerr(stream) PerlIO_clearerr(perlio)
Instead Of: Use:
t* p = malloc(n) Newx(p, n, t)
t* p = calloc(n, s) Newxz(p, n, t)
p = realloc(p, n) Renew(p, n, t)
memcpy(dst, src, n) Copy(src, dst, n, t)
memmove(dst, src, n) Move(src, dst, n, t)
memcpy(dst, src, sizeof(t)) StructCopy(src, dst, t)
memset(dst, 0, n * sizeof(t)) Zero(dst, n, t)
memzero(dst, 0) Zero(dst, n, char)
free(p) Safefree(p)
strdup(p) savepv(p)
strndup(p, n) savepvn(p, n) (Hey, strndup doesn't
exist!)
strstr(big, little) instr(big, little)
strcmp(s1, s2) strLE(s1, s2) / strEQ(s1, s2)
/ strGT(s1,s2)
strncmp(s1, s2, n) strnNE(s1, s2, n) / strnEQ(s1, s2, n)
memcmp(p1, p2, n) memNE(p1, p2, n)
!memcmp(p1, p2, n) memEQ(p1, p2, n)
請注意,Copy
和 Move
的參數順序與 memcpy
和 memmove
中使用的順序不同。
不過,大多數時候,您會希望在內部處理 SV,而不是原始的 char *
字串
strlen(s) sv_len(sv)
strcpy(dt, src) sv_setpv(sv, s)
strncpy(dt, src, n) sv_setpvn(sv, s, n)
strcat(dt, src) sv_catpv(sv, s)
strncat(dt, src) sv_catpvn(sv, s)
sprintf(s, fmt, ...) sv_setpvf(sv, fmt, ...)
另請注意 sv_catpvf
和 sv_vcatpvfn
的存在,它們將串接與格式化結合在一起。
有時,您應該考慮「毒化」資料,而不是使用 Newxz() 將已配置的堆歸零。這表示將位元模式寫入其中,此模式應作為指標(和浮點數)是非法的,而且也希望足夠令人驚訝,因此任何嘗試在未經深思熟慮的情況下使用資料的程式碼都會盡快中斷。可以使用 Poison() 巨集來毒化,其參數與 Zero() 類似
PoisonWith(dst, n, t, b) scribble memory with byte b
PoisonNew(dst, n, t) equal to PoisonWith(dst, n, t, 0xAB)
PoisonFree(dst, n, t) equal to PoisonWith(dst, n, t, 0xEF)
Poison(dst, n, t) equal to PoisonFree(dst, n, t)
Perl 實作了多種類型的字元類別測試。這裡描述的只有那些直接對應於對 8 位元字元執行的 C 函式庫函式的函式,但有對應於寬字元和 UTF-8 編碼字串執行的等效函式。所有函式都在 "perlapi 中的「字元分類」 和 "perlapi 中的「字元大小寫變更」 中有更完整的說明。
下表中列出的 C 函式庫常式會根據目前區域設定傳回值。請使用最後一欄中的項目來取得該功能。其他兩欄總是假設 POSIX(或 C)區域設定。ASCII 欄中的項目僅對 ASCII 輸入有意義,對於其他任何輸入都會傳回 FALSE。僅在您知道這是您要的內容時才使用這些項目。Latin1 欄中的項目假設非 ASCII 8 位元字元為 Unicode 定義的字元,與 ISO-8859-1 相同,通常稱為 Latin 1。
Instead Of: Use for ASCII: Use for Latin1: Use for locale:
isalnum(c) isALPHANUMERIC(c) isALPHANUMERIC_L1(c) isALPHANUMERIC_LC(c)
isalpha(c) isALPHA(c) isALPHA_L1(c) isALPHA_LC(u )
isascii(c) isASCII(c) isASCII_LC(c)
isblank(c) isBLANK(c) isBLANK_L1(c) isBLANK_LC(c)
iscntrl(c) isCNTRL(c) isCNTRL_L1(c) isCNTRL_LC(c)
isdigit(c) isDIGIT(c) isDIGIT_L1(c) isDIGIT_LC(c)
isgraph(c) isGRAPH(c) isGRAPH_L1(c) isGRAPH_LC(c)
islower(c) isLOWER(c) isLOWER_L1(c) isLOWER_LC(c)
isprint(c) isPRINT(c) isPRINT_L1(c) isPRINT_LC(c)
ispunct(c) isPUNCT(c) isPUNCT_L1(c) isPUNCT_LC(c)
isspace(c) isSPACE(c) isSPACE_L1(c) isSPACE_LC(c)
isupper(c) isUPPER(c) isUPPER_L1(c) isUPPER_LC(c)
isxdigit(c) isXDIGIT(c) isXDIGIT_L1(c) isXDIGIT_LC(c)
tolower(c) toLOWER(c) toLOWER_L1(c)
toupper(c) toUPPER(c)
若要強調您僅操作 ASCII 字元,您可以在 ASCII 欄中的每個巨集後面加上 _A
:isALPHA_A
、isDIGIT_A
等。
(即使有 isASCII_L1
,它與 isASCII
相同,但 Latin1 欄中沒有 isascii
的項目;後者的名稱較為清楚。Latin1 欄中沒有 toupper
的項目,因為結果可能是非 Latin1。您必須使用 toUPPER_uvchr
,如 "Character case changing" in perlapi 中所述。)
Instead Of: Use:
atof(s) Atof(s)
atoi(s) grok_atoUV(s, &uv, &e)
atol(s) grok_atoUV(s, &uv, &e)
strtod(s, &p) Strtod(s, &p)
strtol(s, &p, n) Strtol(s, &p, b)
strtoul(s, &p, n) Strtoul(s, &p, b)
典型用法是在轉換類型之前對 uv
進行範圍檢查
int i; UV uv;
char* end_ptr = input_end;
if (grok_atoUV(input, &uv, &end_ptr)
&& uv <= INT_MAX)
i = (int)uv;
... /* continue parsing from end_ptr */
} else {
... /* parse error: not a decimal integer in range 0 .. MAX_IV */
}
另外請注意 numeric.c 中的 grok_bin
、grok_hex
和 grok_oct
函數,用於將表示數字的字串轉換為 NV
。請注意,grok_atoUV() 不處理負輸入或前導空白(故意嚴格)。
請注意,strtol() 和 strtoul() 可能偽裝成 Strtol()、Strtoul()、Atol()、Atoul()。也請避免使用這些函數。
理論上,如果 Perl 建置的機器實際上沒有 strtol 和 strtoul,則可能未定義 Strtol
和 Strtoul
。但由於這 2 個函數是 1989 年 ANSI C 規格的一部分,因此我們認為您現在可以在任何地方找到它們。
int rand() double Drand01()
srand(n) { seedDrand01((Rand_seed_t)n);
PL_srand_called = TRUE; }
exit(n) my_exit(n)
system(s) Don't. Look at pp_system or use my_popen.
getenv(s) PerlEnv_getenv(s)
setenv(s, val) my_setenv(s, val)
您甚至不應該想要使用 setjmp.h 函數,但如果您認為需要,請改用 scope.h 中的 JMPENV
堆疊。
對於 signal
/sigaction
,請使用 rsignal(signo, handler)
。