# GNU C 函式庫常見問題（FAQ）

#### 本文試著回答使用者在安裝與使用 glibc 時可能遭遇的問題，請您在發問或回報 bug（程式錯誤）給維護者之前，先確定您已經讀過這份文件。 <a href="#h.fyxd9ygum0rw_l" id="h.fyxd9ygum0rw_l"></a>

GNU C 函式庫很複雜，安裝的過程還沒有完全的自動化；有太多變數，沒有正確的安裝函式庫會對系統造成實質的傷害，在您開始之前先確定您已經了解你能承擔這一切。

**\[編譯 glibc]**

**GNU C 函式庫可以在哪些系統上面運作呢？**

細節請參考 [README](http://www.google.com/url?q=http%3A%2F%2Fsourceware.org%2Fgit%2F%3Fp%3Dglibc.git%3Ba%3Dblob_plain%3Bf%3DREADME%3Bhb%3DHEAD\&sa=D\&sntz=1\&usg=AOvVaw317Od_yIt0XnECP6-bYMp6) 檔案。

GNU C 函式庫能支援使用 Linux kernel 的這些組態（configurations）：

i\[4567]86-\*-linux-gnu

x86\_64-\*-linux-gnu

powerpc-\*-linux-gnu Hardware floating point required

powerpc64-\*-linux-gnu

s390-\*-linux-gnu

s390x-\*-linux-gnu

sh\[34]-\*-linux-gnu Requires Linux 2.6.11 or newer

sparc\*-\*-linux-gnu

sparc64\*-\*-linux-gnu

另外的組態是 ports 目錄的一部分，細節請參考 [README](http://www.google.com/url?q=http%3A%2F%2Fsourceware.org%2Fgit%2F%3Fp%3Dglibc.git%3Ba%3Dblob_plain%3Bf%3DREADME%3Bhb%3DHEAD\&sa=D\&sntz=1\&usg=AOvVaw317Od_yIt0XnECP6-bYMp6)。

**我需要什麼工具來建立 GNU libc 呢？**

您會需要：

GCC, C 與 C++ 編譯器都要［供 testsuite 用途］

GNU binutils

GNU make

Perl

GNU awk

GNU sed

在 Linux 上：Linux kernel header（表頭）檔

修改 glibc 的開發者可能會另外需要：

gperf

GNU autoconf

GNU gettext

GNU texinfo

更多細節請參考使用手冊的 “[Tools for Compilation](http://www.google.com/url?q=http%3A%2F%2Fwww.gnu.org%2Fsoftware%2Flibc%2Fmanual%2Fhtml_node%2FTools-for-Compilation.html\&sa=D\&sntz=1\&usg=AOvVaw2t7C2zg9IuVHIjRTMfcVuG)” 章節，或者閱讀 glibc 原始碼中的 INSTALL 檔案。

**會用到哪些版本的 Linux kernel header 呢？**

Linux kernel 最近的 header 都應該用的到。在編譯 GNU C 函式庫所用到的 header 版本，與使用函式庫所需的 kernel binary（核心執行檔）版本不用一樣。在 kernel 版本比所用的 kernel header 版本還要舊時，GNU C 函式庫是可以正常運作的。反之［用比較舊版的 kernel header 來編譯，並跑較新版的 kernel］則不會如所預期的運作。比如：假設你使用舊版的 kernel header 來編譯 GNU C 函式庫時，你就不能使用新的 kernel 功能。

即使你的系統是使用比較舊的 kernel，我們還是建議你用最新的 kernel header 來編譯 GNU libc。這樣如果你平時想要升級 kernel 版本的話，你就不用重新編譯 libc 了。為了要讓 libc 知道要使用哪一個 header，需要設定 –with-headers 進行切換［例如：–with-headers=/usr/src/linux-3.3/include］。

為了安裝 Linux kernel header，在 kernel source 的樹狀目錄中執行 make header\_install，這在 [kernel 文件](http://www.google.com/url?q=http%3A%2F%2Fgit.kernel.org%2F%3Fp%3Dlinux%2Fkernel%2Fgit%2Ftorvalds%2Flinux.git%3Ba%3Dblob_plain%3Bf%3DDocumentation%2Fmake%2Fheaders_install.txt%3Bhb%3DHEAD\&sa=D\&sntz=1\&usg=AOvVaw2FjDKd_AW4FnP5trwzf6yQ)中會有說明。

**當我在所產生的函式庫上執行 \`nm -u libc.so’ 時，我仍然會有 unresolved symbols（無法解析的符號），這樣正常嗎？**

是的，這是正常的。會有很多種無法解析的符號：

由 linker（連結器）自動產生的 magic symbols（魔術符號）。他們的名稱會類似 \_\_start\_\* 與 \_\_stop\_\*

從 dynamic linker（動態連結器）產生的是以 \_dl\_\* 開頭的符號

weak symbols（弱符號），不需要全部解析（例如 fabs）

一般而言，你要保證你有找到一個真實的程式，它在認定有問題之前就進行 linking（連結）會產生錯誤。

**什麼是所謂的 \`add-ons’（附加元件）？**

為了延伸 glibc，因而有了以不同 packages（套件）發佈的額外 add-ons（附加元件）。目前 nptl、libidn add-ons 是 glibc 的一部分，而 ports add-on 則是另一個 package。

如果要將這些 packages 當作 GNU libc 的一部分來使用的話，只要解開 libc 原始碼目錄中的 tar 檔，並使用 –enable-add-ons 選項來設定組態檔 script。若你只有給 –enable-add-ons 組態，則會試著找出你原始碼目錄中的全部 add-on packages。若你只是想要選擇 add-ons 的子集合時，請用逗號隔開所要啟用的 add-ons 清單：

例如：configure –enable-add-ons=nptl,libidn

Add-ons 可以新增功能［包含全部新的共享函式庫］、覆蓋檔案、對額外的架構提供支援、以及任何相關的事情。現有的 makefiles 處理了多數的工作；只需要重寫一些少數的 stub rules，就能讓全部的事情都能正常運作。

多數的 add-ons 是對特定的 GNU libc 版本緊耦合（tightly coupled），請檢查你用來與 add-ons 一起運作的 GNU libc 版本。

在 glibc 2.2 的 crypt add-on 以及 glibc 2.1 的 localedata add-on 都已經被整合到一般的 glibc distribution 了。crypt 與 localedata 因此不再出 add-ons。還有，linuxthreads 的 add-on 已經過期了，請改用 nptl。

**我的 kernel 幫我模擬了一顆浮點數（floating-point）的 coprocessor，那我還需要啟用 –with-fp 嗎？**

只有某些平台會有相關的問題，如 PowerPC 或 MIPS。GNU libc 的組態必須與你的編譯器所用的 ABI 一致：兩者都要使用同樣的方式設定。

一顆模擬的 FPU 跟真的一樣好，就我所知，C 函式庫與編譯器是會在意的，如果你的機器沒有辦法執行浮點數指令的話，你只需要設定 –without-fp，並依此設定你的編譯器。

喜歡榨乾機器效能的人會想要避免因這麼做而產生的 trap overhead（負荷）。

**為什麼我在使用 librt 時出現了 missing thread functions（找不到執行緒函式）的訊息呢？我根本沒有用 threads。**

這個時候你可能已經搞爛你的系統了，librt 會在內部使用 threads，因而間接隱含的參考到 thread 函式庫。通常這些條件都會自動滿足，不過如果 thread 函式庫不在預期的地方時，你就必須要跟 linker 說 thread 函式庫在哪裡，使用 GNU ld 執行的樣子會類似這樣：

gcc -o foo foo.c -Wl,-rpath-link=/some/other/dir -lrt

/some/other/dir 應該要包含 thread 函式庫，在沒有任何其它的 link 路徑時，ld 會使用所給的路徑（path）去找出隱含參考的函式庫。

**我在 \`make check’ 的過程失敗了，我應該怎麼辦呢？**

testsuite 應該要在你的系統上乾淨地編譯與執行；每次的執行失敗都應該要找出來。如果測試失敗了，你或許一點都不該安裝這個函式庫。

你應該要在 [bugzilla](http://www.google.com/url?q=http%3A%2F%2Fsourceware.org%2Fbugzilla%2F\&sa=D\&sntz=1\&usg=AOvVaw0V90GbUO2E207mmNQXG24h) 中提出研究報告，並盡可能提供詳細的資料。若你要直接進行一個測試，請記得正確地設定環境。如果你想要測試已編譯好的函式庫，而不是你安裝的函式庫，最好的方式是準確複製失敗的命令列指令，並從原始碼中的子目錄執行測試。

有一些沒有與 GNU libc 直接相關的失敗原因：

有些編譯器會產出 buggy（充滿 bugs）的程式碼，在 Alpha 平台上，沒有編譯器能正確得到單精度的複數。然而，gcc-3.2 應該沒問題。

kernel 可能會有 bugs，比如 tst-cpuclock2 test 需要修正為 Linux 3.1（[patch](http://www.google.com/url?q=http%3A%2F%2Fsourceware.org%2Fml%2Flibc-alpha%2F2012-02%2Fmsg00468.html\&sa=D\&sntz=1\&usg=AOvVaw1pToQsvejlZWgeyT_rTOc2)）。

**什麼是 symbol versioning（符號版本）的好處呢？我會需要它嗎？**

Symbol versioning（符號版本）解決的問題是與 interface（介面）的改變有關。一個 interface 的某個版本可以在先前的 GNU C 函式庫版本中引導，但是 interface 或函式的 semantics（語意） 在這期間已經改變了。為了二進位檔案能與舊版相容，新版的函式庫仍然需要幫舊版程式保留原本的 interface。另一方面，新版程式應該使用新的 interface。Symbol versioning 解決了這個問題，GNU libc 預設使用 symbol versioning，除非透過 configure switch（組態切換）將它關閉。

我們奉勸大家要使用 symbol versioning，不然你會發生二進位檔案的不相容－會永遠不相容！你不僅會與之前 GNU libc 版本的二進位檔案不相容，也會與之後全部的版本不相容。這表示你不能執行別人編譯的程式。

**我該如何在我的快速 ix86 電腦上編譯一個 libc 給較慢的 ix86 電腦使用呢? 在安裝 libc 以後，程式會出現 “Illegal Instruction”（不合法的指令）訊息並結束。**

glibc 與 gcc 會在你的電腦上產生一些舊電腦沒有的指令，你需要告訴 glibc 你正在設定的電腦類型，比如你想要設定給 i586 的電腦時，新增 i586。例如：

../configure –prefix=/usr i586-pc-linux-gnu

而且如果你要告訴 gcc 只產生 i586 的程式，只能增加 \`-mcpu=i586′ 到你的 CFLAGS 中（只用 -m586 沒有效果）。

要注意的是，i486 是最舊的支援架構，因為 nptl 需要 atomic（原子）指令，而這些指令是從 i486 開始支援。

**當第一次執行 rpcgen 時，\`make’ 失敗，是發生什麼事呢？我該怎麼修正呢？**

第一次呼叫 rpcgen，即第一次使用最近編譯的 dynamic loader（動態載入器）。若 dynamic loader 有任何問題，比較像是執行 rpcgen 失敗，這裡有許多問題。

唯一的真實解法就是對 loader 進行除錯，並由你自行定義問題。請記得，對於每個架構而言，需要各種 patches（補丁）讓 glibc HEAD 能轉為可執行狀態，最好的行動方針就是定義你是否具有全部所需的 patches。

**為什麼我試著用 GNU CC 編譯 GNU libc 時會得到錯誤訊息：\`#error “glibc cannot be compiled without optimization”‘（＃錯誤 glibc 不能在沒有最佳化之下編譯）？**

有幾個理由可以說明為什麼 GNU C 函式庫在非最佳化編譯之下，無法正確地工作。

在 dynamic loader (\_dl\_start) 啟動初期時，還沒有進行 PLT relocation（重新定位）以前，你不能進行函式呼叫，你必須 inline 你在初期啟動期間會用到的函式，或者呼叫 ［compiler builtins（編譯器內建）］（\_\_builtin\_\*）。

沒有啟用最佳化的 GNU CC 將不能 inline 函式，dynamic loader 在啟動初期時會透過 unrelocated（尚未重新定位的）PLT 與 crash 進行函式呼叫。

很難在未經查核 dynamic linker 程式碼的情況移除這項需求。

其它的理由是因為，在許多案例中的巢狀函式必須 inline，以避免 executable stacks。

在實務上，在編譯時沒有理由不做最佳化，因此，我們要求 GNU libc 在編譯時都要啟用最佳化。

**安裝與設定議題**

**我該如何設定 GNU libc，讓必須的函式庫，如 libc.so 可以放在 /lib，而其它的放到 /usr/lib 呢？**

如同其它全部的 GNU packages，GNU libc 的設計就是使用基底目錄（base directory），並將全部的檔案都安裝到這裡。預設是 /usr/local，因為這樣是安全的（如果安裝在那裡，它不會危及系統）。若你想要安裝 GNU libc 做為系統上的主要 C 函式庫，只要將基底目錄設定為 /usr（如：執行 configure –prefix=/usr ）。

有些系統，像 Linux 有一個檔案系統標準，它在基本的函式庫與其它函式庫間會產生差異。基本的函式庫放置於 /lib，因為這個目錄是要用來在如 / 的同一個磁碟分割區上定位。/usr 子樹可以在其它的分割區/磁碟上找到。若你在 Linux 設定了 –prefix=/usr，那麼就會自動進行。

想要在非 Linux 的系統上將 GNU libc 基本函式庫安裝在系統上的 /lib 時，必須要明確的要求。這裡的 Autoconf 沒有參數，所以你必須使用 configparam’ 檔案（細節請參考 INSTALL’ 檔案）。它包含了：

slibdir=/lib

sysconfdir=/etc

第一行指定基本函式庫的目錄，而第二行指定系統組態檔的目錄。

**我需要使用 GNU CC 來編譯用到 GNU C 函式庫的程式嗎？**

理論上不用，linker 不會管它，但是在使用 GNU CC 的 C 語言擴充之前，要檢查 GNU CC 所需的 header。

然而，目前 glibc 並沒有對預設使用其它編譯器的系統提供移植，所以沒有人能用其它編譯器測試 headers，因此你會遇到困難，如果你遇到困難了，請以 bugs 的方式回報。

還有，在一些地方，GNU 擴充在程式碼的品質上提供了極大的好處，例如：函式庫已經人工最佳化，對某些字串函式的組合語言版本做了 inline，這些都只有 GCC 可以用。

**我透過查詢共用的 libc 檔案，沒有找到這些函式：\`stat’、\`lstat’、\`fstat’、以及 \`mknod’，且在我的 Linux 系統 linking 時有錯誤訊息。要怎麼樣才能正常運作呢？**

<br>

你信不信，stat 與 lstat（以及 fstat 跟 mknod）在 libc.so.6 中都能預期是 undefined references（未定義的參考）！你的問題或許是因為 /usr/lib/libc.so 遺失或不正確；要注意的是，現在這是一個小的文字檔，而不是 libc.so.6 的 symlink（符號連結）。它看起來像這樣：

GROUP ( libc.so.6 libc\_nonshared.a )

**使用 libc 的程式會有翻譯過的訊息，但是其它的行為就沒有本土化（localized）［如：collating order（核對順序）］；這是為什麼呢？**

會自動安裝已翻譯的訊息，但是控制其它行為的 locale database（本土化資料庫）則不會翻譯，在你執行\`make install’以後，你需要執行 localedef 來安裝這個資料庫。例如：設定French Canadian locale（法裔加拿大本土化）只要簡單的執行這個指令：

localedef -i fr\_CA -f ISO-8859-1 fr\_CA

細節請參考程式碼目錄中的 localedata/README。

**我要怎麼幫 NSS 建立資料庫呢？**

若你在 /etc/nsswitch.conf 裡有一筆 “db” 的資料，你應該也要建立資料庫檔案，glibc 原始碼包含一個 Makefile，可以處理所需的轉換與呼叫以建立那些檔案，檔案位在 nss 子目錄中的 db-Makefile，而你能用 \`make -f db-Makefile’ 來呼叫它。請注意，不是全部的服務都能使用資料庫。

**我無法接受連靜態連結的程式都需要用到一些共享函式庫。我能做什麼呢？**

NSS（關於細節只需輸入\`info libc “Name Service Switch”‘）沒有共享函式庫就無法正常運作，NSS 可以只改變一個組態檔就能使用不同服務（如：NIS、檔案、db、hesiod），而不用重新連結任何程式。但是唯一的缺點是目前的靜態函式庫會需要存取共享函式庫，這個會由 GNU C 函式庫透明化處理。

一個解決方案是以 –enable-static-nss 設定 glibc，在這個例子中，你可以建立一個靜態的執行檔，只能用 dns 與檔案服務（這麼做需修改 /etc/nsswitch.conf），你需要對全部的服務進行明確地連結。例如：

gcc -static test-netdb.c -o test-netdb \\

-Wl,--start-group -lc -lnss\_files -lnss\_dns -lresolv -Wl,--end-group

這個方法的問題在於，你必須使用全部的那些函式來連結每個使用 NSS routines（常式）的靜態程式。

事實上，不要再說用這個選項所編譯的 libc 是使用 NSS 了，不會再有任何的 switch（切換）。因此，強烈建議不要使用 –enable-static-nss，因為這會讓程式在系統中的行為不一致。

**我需要開啟很多檔案，我必須做什麼事呢？**

首先，這是個 kernel 議題，kernel 在 OPEN\_MAX 定義同時開啟檔案的數目，並用 FD\_SETSIZE 定義使用的 file descriptors（檔案描述子）數目。你需要改變 kernel 中的這些值，並重新編譯 kernel，如此一來 kernel 才會允許開啟更多檔案。你不用重新編譯 GNU C 函式庫，因為在函式庫本身中，唯一真正需要 OPEN\_MAX 與 FD\_SETSIZE 的地方是 fd\_set 的大小，這個只有 select 會用到。

GNU C 函式庫現在是 select free（免用 select）的，這表示它的內部不會受限於 fd\_set 型別，將每個需要這個功能的地方改用 poll 函式。

若你在 kernel 中增加 file descriptors 的數目，你就不需要重新編譯 C 函式庫。

你可以在任何時候取得一個 process 允許開啟的 file descriptors 最大數量，使用：

number = sysconf (\_SC\_OPEN\_MAX);

即使 kernel 的限制改變了，這個方法也能正常運作。

**為什麼從不將 glibc 安裝在 GNU/Linux 系統的 /usr/local 資料夾中呢？**

GNU C 編譯器用特殊的方式來看待目錄 /usr/local/include 與 /usr/local/lib，會在系統目錄之前先搜尋這些目錄，因為在 GNU/Linux，系統目錄 /usr/include 與 /usr/lib 包含一個 — 可能不一樣的 — glibc 版本，且混合了其它不受支援及將中止的 glibc 版本某些檔案，這將帶來損壞你整個系統的風險。若你想要測試所安裝的 glibc，以 –prefix 並使用其它的目錄做為參數；若你想要將這個 glibc 版本安裝為預設的版本，使用 –prefix=/usr 覆蓋掉現有的檔案，而全部的東西都會安裝到對的地方。

**原始碼與二進位檔案不相容**

**\`connect’, \`accept’, \`getsockopt’, \`setsockopt’, \`getsockname’, \`getpeername’, \`send’, \`sendto’, and \`recvfrom’ 的原型在 GNU libc 與我在其它系統所見到的不一樣。這是 bug，不是嗎？**

不是的，這不是 bug。GNU libc 已遵循 Single Unix 規格（而我認為 POSIX.1g 草案採用了這個解決方案），描述大小的參數型別是 socklen\_t。

**為什麼不再呼叫訊號中斷系統（signals interrupt system）呢？**

GNU libc 在 signal() 預設是使用 BSD semantics，不像 Linux libc 5，它使用 System V semantics。這一部分相容於其它的系統，而另一部分是由於 BSD semantics 有助於讓 signal 程式設計比較簡單。

有三個差異之處：

在系統呼叫中發生的 BSD 風格 signal 不會影響到系統呼叫；而 System V signals 會讓系統呼叫失敗，並將 errno 設定為 EINTR。BSD signal handlers（訊號處理常式）在觸發之後依然還裝載著，而 System V signal handlers 確只會執行一次，所以每次執行過後都必須要重新安裝。BSD signal 在執行本身的 handler 期間會發生 block，換句話說，不用擔心其它的 SIGCHLD 會中斷 SIGCHLD 的 handler［舉例］，然而，這樣會被其它的 signals 中斷。在使用 signals 進行完好程式設計（casual programming）的一般共識是傾向 BSD semantics 的。你不用擔心系統呼叫會傳回 EINTR，而且也不用擔心與一次性 signal handlers 有關的 race conditions （競速狀況）。

若你正在移植使用舊 semantics 的程式，你可以將全部的 signal() 改變為 sysv\_signal()，以快速修正問題。此外，在引用 \<signal.h> 之前要先定義 \_XOPEN\_SOURCE。

對於新版的程式，sigaction() 函式可以讓你精確地指定要讓 signals 如何運作。上面所述的三個差異點，可以使用這個函式以基於個別 signal 分別獨立切換。

若你只是需要一個特定 signal，可以讓系統呼叫失敗並傳回 EINTR［例如：實作一個 timeout］，那麼你可以用 siginterrupt() 來做。

**我在編譯使用特定字串函式的程式時收到錯誤，為什麼？**

glibc 有特殊的字串函式，可以比一般的函式庫函式還快。部分函式另外以 inline 函式實作，而有些用 macros（巨集）實作，這樣可能會導致現有的程式碼出問題，但是這是由 ISO C 明確許可的。

最佳化過的字串函式只有用在以最佳化編譯時（-O1 或更高），行為能用兩個 feature macros（功能巨集）來改變：

\_\_NO\_STRING\_INLINES：不要進行任何的字串最佳化。

\_\_USE\_STRING\_INLINES：使用組合語言 inline 函式（可能會明顯地增加程式碼的大小）。

因為這些字串函式有一些現在已經另外定義為 macros，類似 “char \*strncpy();” 的程式碼不再能正常運作（而且不需要，因為 \<string.h> 有所需的宣告），只能選擇改變你的程式碼或定義 \_\_NO\_STRING\_INLINES。

在這裡的另一個問題是 gcc 在 registers（暫存器）很少的機器上（如：ix86）仍然會有一些問題，inline 組譯碼幾乎會用到全部的 registers，且 register allocator（暫存器配置者）不能一直處理這種情況。

一種方法是選擇性的關閉字串最佳化，或者是改寫成：

cp = strcpy (foo, "lkj");

一種寫法是：

cp = (strcpy) (foo, "lkj");

這會關閉特定呼叫的最佳化。

**我在使用 stdin/stdout/stderr 時收到編譯器的訊息 “Initializer element not constant” （初始者成員不是常數）。為什麼呢？**

類似這樣的寫法:

static FILE \*InPtr = stdin;

會導致發生這個訊息，在 glibc 這是正確的行為，因為 stdin 不是常數表示，請注意，ISO C 的嚴格讀取並不接受上述的寫法。

這樣的其中一個好處是你能指定給 stdin、stdout 與 stderr，就像任何其它的全域變數（global variable）［例如：stdout = my\_stream;］，這樣會很有用，你可以用 libio 來寫自訂的 streams。［但是要注意，這個不必是可移植的］。以這個方式實作的理由是 FILE structure 大小的版本問題。

為了修正那些問題，你要在執行期就初始化變數，比如說可以這麼做，例如：在 main 中，像這樣：

static FILE \*InPtr;

int main(void)

{

InPtr = stdin;

}

或者以 constructors［要注意這是 gcc 才有的］：

static FILE \*InPtr;

static void inPtr\_construct (void) \_\_attribute\_\_((constructor));

static void inPtr\_construct (void) { InPtr = stdin; }

**我在 \`gcc -ansi’ 時出現一些錯誤，glibc ANSI 不相容嗎？**

GNU C 函式庫相容於 ANSI/ISO C 標準，若你使用 \`gcc -ansi’，glibc 會遵循標準 incldue 標準所規範的。ANSI/ISO C 標準定義了要 include 的檔案，並也說明在 include 檔案中不該

有任何東西［順便提一下，你仍然可以使用某些功能旗標來啟用額外的標準］。

GNU C 函式庫符合 ANSI/ISO C，若且唯若你只使用標準的 headers 與函式庫函式。

**我都不能存取某些函數了，nm 顯示它們存在，不過連結失敗。**

在 glibc 2.1 的版本介紹中，可能只匯出這些應用程式與 glibc 其它部分真正正需要的 identifiers［函式、變數］，許多 internal interface（內部的介面）目前都隱藏起來了。nm 仍然會顯示這些 identifiers，但是會將它們標示為 internal。ISO C 談到，以底線開頭的 identifiers 對 libc 而言都是 internal。應用程式一般應該不會使用這些 internal interface［有些例外，比如：\_\_ivaliduser］。若程式用到這些 interfaces，它會發生 broken（損壞）。這些 internal interface 在 glibc 釋出的版本間可以改變，或者完全捨棄。

**sys/sem.h 檔案缺少 \`union semun’ 的定義。**

不是的，這個 union 必須由使用者的程式提供。以前的 glibc 版本定義了這件事，但是它是個錯誤，因為想一想其實它很不合理，描述 System V IPC 函式的標準定義了它，因此程式必須要採用。

**當我對 setmntent() 傳回的 FILE\* 呼叫 fclose()時，我的程式發生 segfaults（記憶體區段錯誤），這是 glibc 的 bug 嗎？**

不，別這麼做。使用 endmntent()，這就是它的用途。

一般而言，你應該使用正確的解除配置機制（deallocation routine），例如：若你使用 fopen() 開啟檔案，你應該使用 fclose() 解除配置 FILE\*，而不是 free()，即使是 FILE \* 也是個指標。

在 setmntent() 案例中，它可以在多數案例中運作，但是它不一定都能正常運作。無疑地，為了相容性的理由，我們不能將 setmntent() 的回傳型別改為 FILE \* 以外的東西。

**我收到 “undefined reference to \`atexit'”。**

這表示你的安裝幾乎失敗了，這種情況與 stat()、fstat()等一樣［參考問題 2.7］。研究為什麼 linker 不會使用 libc\_nonshared.a。

若在執行期產生了類似的訊息，這表示應用程式或 DSO 沒有連結到 libc。這樣會產生問題，因為 atexit() 不再匯出了。

**雜項**

**我該如何正確地設定 timezone 呢？**

首先你要自己安裝 timezone 資料庫，它架設在 [http://www.iana.org/time-zones](http://www.google.com/url?q=http%3A%2F%2Fwww.iana.org%2Ftime-zones\&sa=D\&sntz=1\&usg=AOvVaw1QKjoooPjbuVTRkUvI3ZGQ)。

然後，直接執行 tzselect shell script，建立一個 /etc/localtime symlink（符號連結）指向 /usr/share/zoneinfo/NAME［NAME 是 tzselect 的傳回值］，回答問題並使用後面印出的名字。就這樣，你不用再擔心了。取代系統全部的 /etc/localtime}} 設定，你也可以設定 {{{TZ 環境變數。

GNU C 函式庫支援擴充的 POSIX method，用來設定 TZ 變數，這個記錄在 [使用手冊](http://www.google.com/url?q=http%3A%2F%2Fwww.gnu.org%2Fsoftware%2Flibc%2Fmanual%2Fhtml_node%2FTZ-Variable.html%23TZ-Variable\&sa=D\&sntz=1\&usg=AOvVaw067GIMV1tillEoexU76YoM)。

**有哪些關於 glibc 的文件來源呢？**

glibc 手冊是 glibc 的一部分，它能由此下載：[線上](http://www.google.com/url?q=http%3A%2F%2Fwww.gnu.org%2Fsoftware%2Flibc%2Fmanual%2F\&sa=D\&sntz=1\&usg=AOvVaw3hGuqLko2kHL0OIUrkpJof).

[Linux man-pages project](http://www.google.com/url?q=http%3A%2F%2Fwww.kernel.org%2Fdoc%2Fman-pages%2F\&sa=D\&sntz=1\&usg=AOvVaw1RxqJLlPMUeyARmsgobSsq) 有關於 Linux kernel 與 C 函式庫 interfaces 的文件。

glibc 的官方網站在：[http://www.gnu.org/software/libc](http://www.google.com/url?q=http%3A%2F%2Fwww.gnu.org%2Fsoftware%2Flibc\&sa=D\&sntz=1\&usg=AOvVaw0atcGz1nS5pXGxgiTMtufn)。

glibc wiki 在[http://sourceware.org/glibc/wiki/HomePage](http://www.google.com/url?q=http%3A%2F%2Fsourceware.org%2Fglibc%2Fwiki%2FHomePage\&sa=D\&sntz=1\&usg=AOvVaw2dgfLYBInael2z5Lt_yGxL)。

對於 bugs，glibc 專案使用 ‘glibc’ 元件的 [sourceware bugzilla](http://www.google.com/url?q=http%3A%2F%2Fsourceware.org%2Fbugzilla%2F\&sa=D\&sntz=1\&usg=AOvVaw0V90GbUO2E207mmNQXG24h)。

**我該如何找出我現在使用的 glibc 是哪個版本呢？**

若你想要從命令列簡單的找出所執行的 libc 執行檔版本，這或許不是每個平台都能做到，但是能用簡單的方式定位出 libc 共享函式庫，並以應用程式啟用，在 Linux 類似這樣：

/lib/libc.so.6

這將會產生全部你所需要的資訊。

一定能正常運作的方法是用 glibc 所提供的 API，編譯並執行下列的小程式就可以取得版本資訊：

\#include \<stdio.h>

\#include \<gnu/libc-version.h>

<br>

int main (void)

{

puts (gnu\_get\_libc\_version ());

return 0;

}

如果需要這個的話，這個 interface 也能用來在執行期執行測試。

**從 signal handlers（訊號處理常式）中使用 setcontext() 不會正常進行 Context switch。**

**XXX: 接下來還是對的嗎？**

setcontext() 的 Linux 實作［IA-64、S390 等］只支援同步的 context switches，這麼做有幾個理由：

UNIX 沒有提供有效同步 context switch［所謂的 co-routine switch］的其它［可移植］方法。有些版本透過 setjmp()/longjmp() 支援這項功能，但是這不是通用的方法。

如同 UNIX ’98 標準所定義的，唯一的方法 setcontext() 可以觸發非同步的 context switch，即若這個函式由 ucontext\_t 指標以第三個參數傳遞給 signal handler 時被呼叫。但是依據 draft 5、XPG6、XBD 2.4.3，setcontext() 不是在可以由 signal handler 呼叫的 routines 集合中。

若 setcontext() 用在非同步 context switches 中，各種同步與 re-entrancy 的議題都會產生，且這些問題已經由真正的多執行緒函式庫［如：POSIX 執行緒］解決了。同步 context switching 可以完全在使用者層（user-level）實作，且需要儲存/回存的狀態比非同步 context switch 要少。因此，可以用它來辨別兩種 context switches 的差異，的確，一些應用程式的供應商都知道要使用 setcontext() 在一般的［heavier-weight］pre-emptable 執行緒上實作 co-routines。

應該要注意的是，若有人對 signal handler 的第三個參數上使用 setcontext()，那麼 IA-64 Linux 可以特過特殊的 sigaction() 版本來支援這個功能，sigaction() 讓全部的 signal handlers 在一個 shim 函式中開始執行，shim 函式負責在呼叫真正的 signal handler 以前儲存保存的 registers，並在之後將它們回存。換句話說，我們能提供一個相容層，用來支援非同步 context switches 的 setcontext()。然而，我不認為上面所給的參數是合理的。setcontext() 提供了一個良好的 co-routine interface，而且我們應該只要勸阻任何非同步的使用［這只會招來麻煩］。

**尚未完成的新 FAQ 記錄**

下列的記錄並非 glibc git repository 中現有 FAQ 的一部分。請自由新增這邊的記錄，爾後將會被移到適當的地方。

**libm 函式的準確度目標是多少呢？**

請參考 [libc-alpha message](https://www.google.com/url?q=https%3A%2F%2Fsourceware.org%2Fml%2Flibc-alpha%2F2013-05%2Fmsg00132.html\&sa=D\&sntz=1\&usg=AOvVaw1DZgWrJY4cNSrSvMwFOaJP)，它詳細的討論了目標。除了類似 sqrt、fma 與 rint 這些用來綁到特定 IEEE 754 操作的函式，以及完整定義來正確地對全部的 rounding modes（對齊模式）進行對齊的結果（包含產生的例外），libm 函式不會特地正確地對齊，在 lulp 以下不會特地產生錯誤（對某些輸入可以有高達部分 ulp 的錯誤），且在底層數學函式是 monotonic （單調）的區域（regions）不會特定是 monotonic。一個綁定到 IEEE 754-2008 的 C 集合草案正在進行中，為了正確地對齊函式，期待將部分（TS 18661-4）定義成名為 crsin 的標準，且在未來的 glibc 能提供類似這類命名的函式。

**為什麼 libm 函式在一些輸入（inputs）中很慢呢？**

GNU C 函式庫包括一個數學函式庫，IBM 贊助了數量可觀的程式碼。IBM 程式碼使用特殊的演算法來幫特定數學函式的輸入計算近似結果。在一些案例中，為了提供精準的最終結果，中繼在運算期間的運算結果也需要有高精準度。實際上有很多學術研究想要證明，最大的精確度需要從中繼結果產生給予精確度的輸出［這些證據通常是依據每個函式而定］。若中繼結果所要求的較高精準度是硬體支援的，則函式會模擬所要求的高精確度。若你需要 100 個 bits，你一起聯合足夠的整數來模擬 100 個 bits，並使用特殊的演算法對那些大數進行操作以取得結果。最後，100 個 bits 的結果會向下對齊 float（浮點數）的大小，或者是 long double，這由所呼叫函式決定。然而，函式的輸入可能需要較高的精確度中繼計算（precision intermediate calculations），這可以輪流使用比較慢的整數多重精確度的值（integer multi-precision values）來計算一個精準的結果。如果沒有較高的中繼精確度，函式的精準度會很糟糕。你可以對幾個 libm 函式中的 slow paths 使用 libm systemtap 探測點（probe points），來偵測你是否正在呼叫 slow path。我們期盼你之後能夠使用探測觸發資訊來微調你的程式碼，以避免 slow paths。社群正在研究提供一種比 libm 快速的替代實作，或許可以用 -ffast-math 所選用的，這可以跳過在精確度的 slow paths 開支，並提供較快速的結果。

**為什麼沒有 strlcpy / strlcat?**

為了避免在修改大型的現有程式碼時，沒有詳細了解程式碼而導致 buffer overruns（過度使用緩衝區），已經[推廣](http://www.google.com/url?q=http%3A%2F%2Fstatic.usenix.org%2Fevent%2Fusenix99%2Fmillert.html\&sa=D\&sntz=1\&usg=AOvVaw0d1dZ-pT5yOwmONTRKK1yT)以更安全的字串複製方式 strlcpy 與 strlcat 函式。[C11 標準](http://www.google.com/url?q=http%3A%2F%2Fen.wikipedia.org%2Fwiki%2FC11_%2528C_standard_revision%2529\&sa=D\&sntz=1\&usg=AOvVaw01GMKzXiCskeg6CRnD2LTE)的 Annex K 定義了選配式函式 strcpy\_s 與 strcat\_s，提供類似的需求，儘管以不一樣的 calling concentions（呼叫慣例）會比較沒有效率。無庸置疑的是實作這些函式會有問題，因為它們打算默默的將資料截斷、增加複雜度與降低效率、且沒有防止全部目地的 buffer overruns。新的標準函式庫函式應該考慮現有實作的優點，並且對於 glibc 已忽略的這些函式是好的實作不是很清楚。

以 gcc -D\_FORTIFY\_SOURCE 進行編譯可以捕捉到許多函式預期能捕獲的錯誤，而不需要修改程式碼。還有，若效率不是最重要的，snprintf 函式通常能做為這些函式的可移植替代品。

**在 ARM 編譯失敗**

你需要使用 ports add-on。

**我該如何打造一個在舊版 GNU/Linux distributions 上執行的二進位檔呢？**

［使用針對 LSB 的回答，利用 distro LSB packages 的相關資訊］。

**我該如何在 Ubuntu 上面打造 glibc 呢？［這裡列出其它 distributions 的類似問題］**

有些 distribution 的編譯器預設會啟用 -fstack-protector。GNU C 函式庫無法以它來編譯，因此你需要在 CFLAGS 新增 “-fno-stack-protector -U\_FORTIFY\_SOURCE”。

**在安裝 glibc 2.15 之後，我就不能編譯 GCC 了**

忠告：然而，遇到類似 siginfo\_t 變更與建立 libgcc 失敗相關的新問題是有幫助的，現有的 GCC releases［比 Thomas 還早的 patches］不能用目前的 glibc 來建立。

原文：[Frequently Asked Questions about the GNU C Library](http://www.google.com/url?q=http%3A%2F%2Fsourceware.org%2Fglibc%2Fwiki%2FFAQ\&sa=D\&sntz=1\&usg=AOvVaw1Fz5YrptMzYUQvJXfpcNvp)

譯者：Aaron Liao (<aaron@netdpi.net>)，對於譯文有任何建議請留言，謝謝。

修訂：2014/04/06，本中文版參照 [CarlosODonell](https://www.google.com/url?q=https%3A%2F%2Fsourceware.org%2Fglibc%2Fwiki%2FCarlosODonell\&sa=D\&sntz=1\&usg=AOvVaw39P5FySIB_jfccbcjuuFP4) 2013-11-28 22:22:49 編輯的版本

授權：[GPL](http://www.google.com/url?q=http%3A%2F%2Fmoinmo.in%2FGPL\&sa=D\&sntz=1\&usg=AOvVaw02SkdDZqX0Oo2WCypPbGH-)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://applezulab.netdpi.net/glibc-doc/glibc-lib-faq.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
