== Part 4/4 ============================
comp.lang.c++ Frequently Asked Questions list (with answers, fortunately).
Copyright (C) 1991-96 Marshall P. Cline, Ph.D.
Posting 4 of 4.
Posting #1 explains copying permissions, (no)warranty, table-of-contents, etc
=======================================
■□ 第17節:和 C 連結/和 C 的關係
=======================================
Q105:怎樣從 C++ 中呼叫 C 的函數 "f(int,char,float)"?
告訴 C++ 編譯器說:它是個 C 的函數:
extern "C" void f(int,char,float);
確定你有 include 進來完整的函數原型 (function prototype)。一堆 C 的函數可
以用大括號框起來,如下:
extern "C" {
void* malloc(size_t);
char* strcpy(char* dest, const char* src);
int printf(const char* fmt, ...);
}
========================================
Q106:怎樣才能建一個 C++ 函數 "f(int,char,float)",又能被 C 呼叫?
想讓 C++ 編譯器知道 "f(int,char,float)" 會被 C 編譯器用到的話,就要用到前
一則 FAQ 已詳述的 "extern C" 語法。接著在 C++ 模組內定義該函數:
void f(int x, char y, float z)
{
//...
}
"extern C" 一行會告訴編譯器:送到 linker 的外部資訊要採用 C 的呼叫慣例及簽
名編碼法(譬如,前置一個底線)。既然 C 沒有多載名稱的能力,你就不能讓 C 程
式能同時呼叫得到多載的函數群。
警告以及實作相關事項:
* 你的 "main()" 應該用 C++ 編譯之(為了靜態物件的初始化)。
* 你的 C++ 編譯器應該能設定連結的程序(為某些特殊的程式庫)。
* 你的 C 和 C++ 編譯器可能要是同一個牌子的,而且是相容的版本(亦即:有相
同的呼叫慣例等等)。
========================================
Q107:為什麼 linker 有這種錯誤訊息:C/C++ 函數被 C/C++ 函數呼叫到?
看前兩則 FAQs 關於 extern "C" 的使用。
========================================
Q108:該怎麼把 C++ 類別的物件傳給/傳自 C 的函數?
例子:
/****** C/C++ header file: Fred.h ******/
#ifdef __cplusplus /*"__cplusplus" is #defined if/only-if
compiler is C++*/
extern "C" {
#endif
#ifdef __STDC__
extern void c_fn(struct Fred*); /* ANSI-C prototypes */
extern struct Fred* cplusplus_callback_fn(struct Fred*);
#else
extern void c_fn(); /* K&R style */
extern struct Fred* cplusplus_callback_fn();
#endif
#ifdef __cplusplus
}
#endif
#ifdef __cplusplus
class Fred {
public:
Fred();
void wilma(int);
private:
int a_;
};
#endif
"Fred.C" 是個 C++ 模組:
#include "Fred.h"
Fred::Fred() : a_(0) { }
void Fred::wilma(int a) : a_(a) { }
Fred* cplusplus_callback_fn(Fred* fred)
{
fred->wilma(123);
return fred;
}
"main.C" 是個 C++ 模組:
#include "Fred.h"
int main()
{
Fred fred;
c_fn(&fred);
return 0;
}
"c-fn.c" 是個 C 模組:
#include "Fred.h"
void c_fn(struct Fred* fred)
{
cplusplus_callback_fn(fred);
}
把指向 C++ 物件的指標傳到/傳自 C 的函數,如果傳出與收回的指標不是“完全相
同”的話,就會失敗。譬如,不要傳出一個基底類別的指標卻收回一個衍生類別的指
標,因為 C 編譯器不懂該怎麼對多重及虛擬繼承的指標做轉型。
========================================
Q109:C 的函數能不能存取 C++ 類別的物件資料?
有時可以。
(請先讀一讀前一則關於和 C 函數間傳遞 C++ 物件的 FAQ。)
你可以安全地從 C 函數中存取 C++ 物件的資料,只要 C++ 的物件類別:
* 沒有虛擬函數(包含繼承下來的虛擬函數).
* 所有資料都在同一個存取等級中 (private/protected/public).
* 完全被包含的子物件中也都沒有虛擬函數.
如果 C++ 類別有任何基底類別(或是任何被完全包含的子物件中有基底類別)的話
,技術上來說,存取該資料沒有可攜性的,因為語言沒規定在繼承之下的類別配置是
什麼樣子。不過經驗上,所有 C++ 編譯器的做法都一樣:基底類別物件先出現(在
多重繼承之下,則由左到右排列之),子物件次之。
還有,如果類別(或是任何基底類別)含有任何虛擬函數,你時常可以(但不是一直
都可以)假設有一個 "void*" 出現在物件第一個虛擬函數之所在,或是在該物件的
第一個 word 那裡。同樣的,語言對它也沒規定到,但這似乎是「大家」都採取的做
法。
如果該類別有任何虛擬基底類別,情況會更複雜而且更沒有可攜性。常見的做法是:
讓物件最後才包含基底類別之物件 (V)(不管 "V" 在繼承階層中在哪兒出現),物
件的其他部份則以正常的次序出現。每個有 V 這個虛擬基底類別的衍生類別,實際
上都有個“指標”指向最後一個物件的 V 的部份。
========================================
Q110:為什麼我總覺得 C++ 讓我「離機器更遠了」,不像 C 那樣?
因為事實上正是如此。
做為一個 OOPL,C++ 讓你以該問題的領域來思考,讓你以問題領域的語言來設計程
式,而非以解題的領域來著手。
一個 C 最強的地方是:它沒有「隱藏的機制」:你看到的就是你得到的,你可以一
邊閱讀 C 的程式,一邊「看到」每個系統時脈。C++ 則不然; C 的老手(像從前的
我們)對這種特性常會有矛盾的心理(或是說「敵視」),但是很快的他們會發現:
C++ 提供了抽象化的層次及經濟的表現能力,大大降低維護成本,又不會損及執行效
率。
很自然的,用任何語言都會寫出壞程式;C++ 並不會確保任何高品質、可重用性、抽
象化,或是任何「正字標記」的品質因子。C++ 不會讓差勁的程式者寫不出差勁的程
式;她只是協助明智的發展者做出高人一等的軟體。
===================================
■□ 第18節:指向成員函數的指標
===================================
Q111:「指向成員函數的指標」和「指到函數的指標」的型態有差別嗎?
是的。
考慮底下的函數:
int f(char a, float b);
如果它是普通的函數,它的型態是: int (*) (char,float);
如果它是 Fred 類別的運作行為,它的型態是: int (Fred::*)(char,float);
========================================
Q112:怎樣把指向成員函數的指標傳給 signal handler、X event callback 等等?
【譯註】這是和 UNIX、X Window System 相關的問題,但其他系統亦可推而廣之。
不要這樣做。
因為若無物件去啟動它,成員函數是無意義的,你不能直接使用它(如果 X 視窗系
統是用 C++ 寫的話,或許就可以直接傳物件的參考值了,而不光是傳個指向函數的
指標;自然地,物件會包含所有要用到的函數,甚至更多)。
若想修改現有的軟體,可拿最頂層的(非成員的)函數當作一層包裝 (wrapper),透
過其他技巧(或許是放在全域變數中),把該物件包起來。這個最頂層的函數,會透
過適當的成員函數去使用該全域變數。
譬如,你想在中斷處理中呼叫 Fred::memfn() 的話:
class Fred {
public:
void memfn();
static void staticmemfn(); // 用個 static 成員函數就行了
//...
};
//wrapper 函數會記得哪個物件該去啟動全域物件的成員函數:
Fred* object_which_will_handle_signal;
void Fred_memfn_wrapper() { object_which_will_handle_signal->memfn(); }
main()
{
/* signal(SIGINT, Fred::memfn); */ //不能這樣做
signal(SIGINT, Fred_memfn_wrapper); //Ok
signal(SIGINT, Fred::staticmemfn); //Also Ok
}
注意:靜態成員函數不需要真正的物件才能啟動,所以指向靜態成員函數的指標,和
普通的指向函數的指標,具有相容的型態(詳見 ARM ["Annotated Reference
Manual"] p.25, 158)。
========================================
Q113:當我想以成員函數做為中斷服務常式 (ISR) 時,為什麼編譯器產生(型態不
符)的錯誤?
這是前兩個問題的特例,所以請先看看前兩則解答。
非靜態的成員函數,都有一個隱藏的參數,對應到 'this' 指標,該 'this' 指標會
指向該物件的案例資料 (instance data),可是系統中斷的硬體/韌體並未提供這個
'this' 參數。你得用「正常的」函數(不是類別的成員)或是靜態成員函數來做為
中斷服務常式才行。
一個可行的解法是:用一個靜態成員做為中斷服務常式,讓它能自己到某處去找案例
/成員的配對,以供中斷呼叫之用。這麼一來,當中斷產生時,正常的 method 就會
被啟動,不過以技術觀點來看,你得先呼叫一個中介函數。
========================================
Q114:為什麼我取不出 C++ 函數的位址?
這可由前一則 FAQ 推論過來。
詳細的解答:在 C++ 裡,成員函數有一個隱含的參數,指向該物件本身(成員函數
內的 "this" 指標)。正常的 C 函數與成員函數的呼叫慣例可視為不同,所以它們
指標的型態(指向成員函數 vs 指向函數)既不同也不相容。C++ 引進一個新的指標
型態:指向成員的指標,要提供一個物件才能啟動之(見 ARM ["Annotated
Reference Manual"] 5.5)。
注意:不要去把指向成員函數的指標強制轉型成指向函數的指標;這樣做的結果是未
定義的,且下場可能會很慘。譬如,指向成員函數的指標,“不必然”會包含某正常
函數的機器位址(看 ARM, 8.1.2c, p.158)。如前例所提,如果你有個指向正常 C
函數的指標的話,請用上層的(非成員的)函數,或是用 "static" 成員函數(類別
成員函數)。
========================================
Q115:怎樣宣告指向成員函數的指標陣列?
用 "typedef" 好讓你的腦筋保持清醒。
class Fred {
public:
int f(char x, float y);
int g(char x, float y);
int h(char x, float y);
int i(char x, float y);
//...
};
typedef int (Fred::*FredPtr)(char x, float y);
這是指向成員函數的指標陣列:Here's the array of pointers to member functions:
FredPtr a[4] = { &Fred::f, &Fred::g, &Fred::h, &Fred::i };
呼叫物件 "fred" 的某一個成員函數:
void userCode(Fred& fred, int methodNum, char x, float y)
{
//假設 "methodNum" 在 [0,3] 區間內
(fred.*a[methodNum])(x, y);
}
你可以用 #define 讓這個呼叫清楚些:
#define callMethod(object,ptrToMethod) ((object).*(ptrToMethod))
callMethod(fred, a[methodNum]) (x, y);
====================================
■□ 第19節:容器類別與 template
====================================
Q116:怎樣自一個連結串列/雜湊表等等裡面,插入/存取/改變元素?
我將以最簡單的「插入連結串列」為例。想把元素插入串列的頭尾很容易,但只限
於這些功能的話,會使程式庫過於低能(太低能的程式庫比沒有更糟)。
完整的解答會讓 C++ 新手消化不良,所以我只提幾個項目。第一個是最簡單的,第
二和第三是比較好的。
[1] 替 "List" 加入一個「現在位置」的性質,加入像是 advance()、backup()、
atEnd()、atBegin()、getCurrElem()、setCurrElem(Elem)、insertElem(Elem)
、removeElem() 等等的運作行為。
即使在這個小例子裡已經夠用了,但「只有一個」現在位置的記號的話,想存取
串列中兩個以上位置的元素就不太容易(譬如:「對所有 x,y 序對,做底下的
事情……」)。
[2] 把上述的 List 運作行為拿掉,移到獨立的類別 "ListPosition" 中。
ListPosition 的作用是:代表 List 裡「現在的位置」,這樣就允許許多位置
並存於同一個串列中。ListPosition 是 List 的夥伴,所以 List 的內部可對
外界隱藏起來(否則 List 的內部就會被它的公共運作行為所公開)。注意:
ListPosition 可以把運算子多載起來,像是 advance()、backup(),因為運算
子多載只是正常運作行為的語法糖衣而已。
[3] 把整個位置處理(iteration)當成是一個基元事件(atomic event),建一個
class template 去涵蓋該事件。
它不會在內部迴圈中使用公共存取運作行為(它有可能是虛擬函數),所以效率
能增進。不幸的,你的應用軟體會多出些額外的二元碼,因為 template 是以空
間換取時間的。欲知詳情,請見 [Koenig, "Templates as interfaces,"
JOOP, 4, 5 (Sept 91)], 以及 [Stroustrup, "The C++ Programming Language
Second Edition," under "Comparator"].
========================================
Q117:「樣版」(template)的用意是什麼?
Template 本意是個壓餅模子,它把餅乾都壓成差不多一個樣子(雖然餅乾的原料不
盡相同,但它們都有相同的基本外形)。同理,class template 是個樣版模子,用
來描述如何將一系列的物件類別弄成同一個基本型式;而 function template 則是
用以描述一系列看起來差不多的函數。
Class template 常用於製造型別安全的容器(即使這僅止於「如何使用它」而已)。
========================================
Q118:"function template" 的語法/語意是什麼?
考慮底下這個交換兩個整數引數的函數:
void swap(int& x, int& y)
{
int tmp = x;
x = y;
y = tmp;
}
假如我們想交換 float、long、String、Set 和 FileSystems,我們還得寫那些
大致看起來都一樣、只有型態不同的程式碼,有夠煩人。這種不花腦筋的重複性工作
,正是電腦的專長,於是我們想出了 function template:
template
void swap(T& x, T& y)
{
T tmp = x;
x = y;
y = tmp;
}
每次我們以一組型別來使用 "swap()",編譯器會找到上面這定義,並造出另一個
"template function" ,來當作它的「案例」(instantiation)。譬如:
main()
{
int i,j; /*...*/ swap(i,j); // 案例化 "int" 的 swap
float a,b; /*...*/ swap(a,b); // 案例化 "float" 的 swap
char c,d; /*...*/ swap(c,d); // 案例化 "char" 的 swap
String s,t; /*...*/ swap(s,t); // 案例化 "String" 的 swap
}
(注意:"template function" 是 "function template" 實體化之後的案例。)
========================================
Q119:"class template" 的語法/語意是什麼?
考慮像是個整數陣列的容器類別:
// 這會放在像是 "Array.h" 的標頭檔中
class Array {
public:
Array(int len=10) : len_(len), data_(new int[len]){}
~Array() { delete [] data_; }
int len() const { return len_; }
const int& operator[](int i) const { data_[check(i)]; }
int& operator[](int i) { data_[check(i)]; }
Array(const Array&);
Array& operator= (const Array&);
private:
int len_;
int* data_;
int check(int i) const
{ if (i < 0 || i >= len_) throw BoundsViol("Array", i, len_);
return i; }
};
如同前述的 "swap()" ,一再為 float、char、String、Array-of-String 等等來重
複設計 Array 類別,是很煩人的。
// 這會放在像是 "Array.h" 的標頭檔中
template
class Array {
public:
Array(int len=10) : len_(len), data_(new T[len]) { }
~Array() { delete [] data_; }
int len() const { return len_; }
const T& operator[](int i) const { data_[check(i)]; }
T& operator[](int i) { data_[check(i)]; }
Array(const Array&);
Array& operator= (const Array&);
private:
int len_;
T* data_;
int check(int i) const
{ if (i < 0 || i >= len_) throw BoundsViol("Array", i, len_);
return i; }
};
不像 template function 那樣,template classes(案例化的 class template)必
須將那些用來案例化的參數型態明示出來:
main()
{
Array ai;
Array af;
Array ac;
Array as;
Array< Array > aai;
} // ^^^-- 注意這空格;不要用 "Array>"
// (編譯器會把 ">>" 看成單一的元素)
========================================
Q120:什麼是「參數化型別」(parameterized type)?
另一種 "class template" 的說法。
「參數化型別」是一種型別,它被另一個型別或數值所參數化(parameterized)了。
像 List 是一個型別 ("List") ,它被另一個型別 ("int") 所參數化。
========================================
Q121:「泛型」(genericity)是什麼?
另一種 "class template" 的說法。
不要和「一般化」(generality,指不要過於特定的解題)弄混了,「泛型」指的是
class template。
=======================
■□ 第20節:程式庫
=======================
Q122:怎樣拿到 "STL"?
"STL" 代表 "Standard Templates Library",標準模版程式庫。取得法:
STL HP official site: ftp://butler.hpl.hp.com/stl
STL code alternate: ftp://ftp.cs.rpi.edu/stl
STL code + examples: http://www.cs.rpi.edu/~musser/stl.html
STL hacks for GCC-2.6.3 已經在 GNU libg++ 2.6.2.1 或更新版本裡了(可能較早
的版本也有)。多謝 Mike Lindner。
========================================
Q123:怎樣 ftp 到 "Numerical Recipes" 附的程式?
它是用賣的,把它放到網路上散佈是違法的。不過它只需 $30 美元而已。
========================================
Q124:為什麼我的執行檔會這麼大?
很多人對這麼大的執行檔感到驚訝,特別是當原始碼只有一點點而已。例如一個簡單
的 "hello world" 程式居然會產生大家都想不到的大小(40+K bytes)。
一個原因是:有些 C++ 執行期程式庫被連結進去了。有多少被連結進去,就要看看
你用到多少,以及編譯器把程式庫切割成多少塊而定。例如,iostream 很大,包含
一大堆類別及虛擬函數,即使你只用到一點點,因為各元件之間的交互參考依存關係
,可能會把整個 iostream 程式碼都塞進來了。(【譯註】如果 linker 做得好的話
,應該能把完全用不到的元件 object code 砍掉,不隨之塞入你的執行檔中。)
不要用靜態的,改用動態連結的程式庫版本,就可以使你的程式變小。
欲知詳情,請看看你的編譯器手冊,或是尋求廠商的技術支援。
===============================
■□ 第21節:特定系統的細節
===============================
Q125:GNU C++ (g++) 把小程式造出大大的執行檔,為什麼?
libg++(g++ 用到的程式庫)可能在編譯時帶有除錯的資訊(-g)。有些機器上,不
帶除錯資訊地重新編譯它,會省下很大的磁碟空間(∼1 MB;缺點是:不能追蹤到
libg++ 的呼叫)。僅僅 "strip" 掉執行檔,比不上先用 -g 重新編譯,再 "strip"
掉 a.out 檔來得有效。
用 "size a.out" 來看看執行碼的程式與資料區段到底佔了多大空間,而不要用
"ls -s a.out" 這種包括了符號表格(symbol table)的方式。
========================================
Q126:有 YACC 的 C++ 文法嗎?
Jim Roskind 是 C++ 的 YACC 文法作者,它大體上和部份 USL cfront 2.0 所實作
出來的語言相容(沒有 template、例外、執行期型態識別功能)。這份文法有些地
方和 C++有細小而微妙的差別。
它可用 anonymous ftp 到下列地方取得:
* ics.uci.edu (128.195.1.1) in "gnu/c++grammar2.0.tar.Z".
* mach1.npac.syr.edu (128.230.7.14) in "pub/C++/c++grammar2.0.tar.Z".
========================================
Q127:什麼是 C++ 1.2? 2.0? 2.1? 3.0?
這些不是“語言”的版本,而是 cfront 這個由 AT&T 做出來的、最早的 C++轉譯程
式的版本編號。以這編號來“代表”C++ 語言的演進,已經是公認的慣例了。
“非常”粗略地講,主要的特徵有:
* 2.0 包含多重/虛擬繼承,以及純虛擬函數。
* 2.1 包含半巢狀 (semi-nested) 類別,及 "delete [] 陣列指標"。
* 3.0 包含全巢狀 (fully-nested) 類別、template 和 "i++" vs "++i"。
* 4.0 將包含例外處理。
========================================
Q128:如果簽名編碼標準化了,我能否將不同廠商編譯器產生的程式碼連結起來?
簡短的回答:可能不行。
換句話說,有人希望標準化的簽名編碼規則能併入擬議中的 C++ ANSI 標準,避免還
要為不同廠商的編譯器購買不同版本的物件程式庫。然而不同的系統實作中,簽名編
碼的差異性只佔一小部份而已,即使是在同一個基台(platform)上。這裡列出一部
份其他的差異處:
1) 成員函數隱含的引數個數和型態。
1a) 'this' 有被特殊處理嗎?
1b) 傳值的指標放在哪裡?
2) 假設有用到 vtable 虛擬表格的話:
2a) 它的內容及配置?
2b) 多重繼承時,'this' 在何處/如何調整?
3) 類別如何配置,包含:
3a) 基底類別的位置?
3b) 虛擬基底類別的處理?
3c) 虛擬表格指標的位置,如果有用虛擬表格的話?
4) 函數的呼叫慣例,包含:
4a) 呼叫者還是被呼叫者負責調整堆疊?
4b) 實際參數放到哪裡?
4c) 實際參數傳遞之順序?
4d) 暫存器如何存放?
4e) 傳回值放到哪裡?
4f) 對傳入/傳回 struct 或 double 有無特殊的規定?
4g) 呼叫末端函數(leaf function)有無特殊的暫存器存放規定?
5) run-time-type-identification 如何配置?
6) 當一個例外被 throw 時,執行期的例外處理系統如何得知哪一個區域物件該被解
構?
=======================================
■□ 第22節:其他的技術和環境的事項
=======================================
● 22A:其他的技術事項
========================
Q129:為什麼有 static 資料成員的物件類別產生了 linker 錯誤?
Static 的資料成員必須外顯地在唯一的模組中定義。
^^^^^^ ~~~~~~^^^^ ^^^^
【譯註】這句話要逐字細讀。原文是:Static data members must be
explicitly defined in exactly one module.
譬如:
class Fred {
public:
//...
private:
static int i_; // 宣告 static 資料成員 "Fred::i_"
//...
};
Linker 會告訴你 "Fred::i_ is not defined(未定義)" ,除非你在任何一個(且
唯一)原始檔中定義(而非宣告)了 "Fred::i_" :
int Fred::i_ = 某個會產生 int 的運算式;
或是:
int Fred::i_;
通常我們會在 "Fred.C" 檔中定義 "Fred" 類別的 static 資料成員(或 "Fred.cpp"
等等你使用的副檔名)。
========================================
Q130:"struct" 和 "class" 關鍵字差別在哪?
struct 的成員和基底類別, 都是預設為 public 的,而 class 則預設為 private。
注意:你應該“明顯地”把基底類別設為 public、private 或是 protected,而不
要依賴預設值。
除此之外,兩者的功能是相等的。
========================================
Q131:為什麼不能以函數的傳回值來多載(overload)它?
如果你同時宣告了 "char f()" 及 "float f()" ,編譯器會給你個錯誤訊息,因為
呼叫 "f()" 會造成模擬兩可的情況。
========================================
Q132:什麼是「持續性」?什麼是「持續性物件」?
一個持續性物件 (persistent object),在創造它的程式執行結束後,仍可存活下來
。它甚至可存活於不同的父程式,存活於磁碟系統、作業系統、甚至於作業系統所處
的硬體上。
持續性物件的困難在於:如何有效地在次儲存體中,存放它們的運作行為(method)
及資料位元(以及所有成員物件的資料和運作行為,及它們所有的成員物件、基底類
別……等等)。這一切都得自己來做的話,可不是件容易的事。在 C++中,你就得自
己來。C++/OO 的資料庫系統,會替你把這些機制都隱藏起來。
========================================
Q133:為什麼浮點數 (floating point) 這麼不精確?為什麼這段程式不會印出 0.43?
#include
main()
{
float a = 1000.43;
float a = 1000.0;
cout << a - b << '\n';
}
(附註,有些 C++ 環境下會印出 0.429993)
聲明:受進位/捨位/近似值之苦,其實並不是 C++ 的問題,而是電腦科學界的問
題。不過還是一直有人在 comp.lang.c++ 裡發問,所以我給你一個答案意思一下。
答案:浮點數本來就是個近似值。在 IEEE 的 32 位元浮點數標準裡,有 1 位元的
正負號,8 位元的指數,23 位元的假數。因為正規化後的二進位假數都會變成像是
1.xxxxx... 的型式,所以頭一項的 1 不予計入,就能得到 24 位元的有效假數。
1000.43(以及其他很多很多數字)都不是 float 或 double 的表示法,其實
1000.43 的位元內容是這樣子的('s' 代表正負號,'e' 代表指數,'m' 代表假數)
:
seeeeeeeemmmmmmmmmmmmmmmmmmmmmmm
01000100011110100001101110000101
假數移位後變成 1111101000.01101110000101 或是 1000 + 7045/16384。
分數部份為 0.429992675781。
float 的假數佔 24 位元,所以你只得到 16M 分之一的精確度。
double 有較高的精確度(53 位元的假數)。
==========================
● 22B:其他環境下的瑣事
==========================
Q134:有任何 TeX 或 LaTeX 的巨集,能處理 "C++" 的留白效果(spacing)嗎?
有的,底下列出兩個:
\def\CC{C\raise.22ex\hbox{{\footnotesize +}}\raise.22ex\hbox{\footnotesize +}}
\def\CC{{C\hspace{-.05em}\raisebox{.4ex}{\tiny\bf ++}}}
========================================
Q135:在哪兒可拿到 C++2LaTeX 這個 C++原始碼的 LaTeX 美編工具(pretty
printer)?
這兒列出一些 ftp 地點:
Host aix370.rrz.uni-koeln.de (134.95.80.1) Last updated 15:41 26 Apr 1991
Location: /tex
FILE rw-rw-r-- 59855 May 5 1990 C++2LaTeX-1.1.tar.Z
Host utsun.s.u-tokyo.ac.jp (133.11.11.11) Last updated 05:06 20 Apr 1991
Location: /TeX/macros
FILE rw-r--r-- 59855 Mar 4 08:16 C++2LaTeX-1.1.tar.Z
Host nuri.inria.fr (128.93.1.26) Last updated 05:23 9 Apr 1991
Location: /TeX/tools
FILE rw-rw-r-- 59855 Oct 23 16:05 C++2LaTeX-1.1.tar.Z
Host iamsun.unibe.ch (130.92.64.10) Last updated 05:06 4 Apr 1991
Location: /TeX
FILE rw-r--r-- 59855 Apr 25 1990 C++2LaTeX-1.1.tar.Z
Host iamsun.unibe.ch (130.92.64.10) Last updated 05:06 4 Apr 1991
Location: /TeX
FILE rw-r--r-- 51737 Apr 30 1990
C++2LaTeX-1.1-PL1.tar.Z
Host tupac-amaru.informatik.rwth-aachen.de (192.35.229.9)
Last updated 05:07 18 Apr 1991
Location: /pub/textproc/TeX
FILE rw-r--r-- 72957 Oct 25 13:51 C++2LaTeX-1.1-PL4.tar.Z
Host wuarchive.wustl.edu (128.252.135.4) Last updated 23:25 30 Apr 1991
Location: /packages/tex/tex/192.35.229.9/textproc/TeX
FILE rw-rw-r-- 49104 Apr 10 1990 C++2LaTeX-PL2.tar.Z
FILE rw-rw-r-- 25835 Apr 10 1990 C++2LaTeX.tar.Z
Host tupac-amaru.informatik.rwth-aachen.de (192.35.229.9)
Last updated 05:07 18 Apr 1991
Location: /pub/textproc/TeX
FILE rw-r--r-- 74015 Mar 22 16:23 C++2LaTeX-1.1-PL5.tar.Z
Location: /pub
FILE rw-r--r-- 74015 Mar 22 16:23 C++2LaTeX-1.1-PL5.tar.Z
Host sol.cs.ruu.nl (131.211.80.5) Last updated 05:10 15 Apr 1991
Location: /TEX/TOOLS
FILE rw-r--r-- 74015 Apr 4 21:02x C++2LaTeX-1.1-PL5.tar.Z
Host tupac-amaru.informatik.rwth-aachen.de (192.35.229.9)
Last updated 05:07 18 Apr 1991
Location: /pub/textproc/TeX
FILE rw-r--r-- 4792 Sep 11 1990 C++2LaTeX-1.1-patch#1
FILE rw-r--r-- 2385 Sep 11 1990 C++2LaTeX-1.1-patch#2
FILE rw-r--r-- 5069 Sep 11 1990 C++2LaTeX-1.1-patch#3
FILE rw-r--r-- 1587 Oct 25 13:58 C++2LaTeX-1.1-patch#4
FILE rw-r--r-- 8869 Mar 22 16:23 C++2LaTeX-1.1-patch#5
FILE rw-r--r-- 1869 Mar 22 16:23 C++2LaTeX.README
Host rusmv1.rus.uni-stuttgart.de (129.69.1.12)
Last updated 05:13 13 Apr 1991
Location: /soft/tex/utilities
FILE rw-rw-r-- 163840 Jul 16 1990 C++2LaTeX-1.1.tar
========================================
Q136:該到哪裡取得 "tgrind" 這個 C++/C/etc 的原始碼美編工具?
"tgrind" 讀入 C++ 原始檔案,並輸出能讓 Unix 印表機印出美觀文件的東西。它常
會伴隨在 TeX 和 LaTeX 的套件裡;請找找這個目錄:
"...tex82/contrib/van/tgrind" 。 由 Jerry Leichter 所做更新的版本,可在
venus.ycc.yale.edu in [.TGRIND] 裡找到。
========================================
Q137:有給 GNU emacs 編輯器用的 C++-mode 嗎?有的話,該怎麼拿?
Yes,有一個給 GNU emacs 用的 C++-mode。
最新、最好的 C++-mode(以及 c-mode)版本是 cc-mode.el 檔,是 Detlef &
Clamen 版本的延伸。Emacs 裡頭有一個了,較新的則在 elisp 裡面。
========================================
Q138:我要到哪兒得到和作業系統相關的 FAQs( 譬如:BC++、DOS、Windows 等等
)?
請參考:
* comp.os.msdos.programmer
* comp.windows.ms.programmer
* comp.unix.programmer
[如果您有 BC++、VC++ 的 email address,或是 Semantic C++ 的臭蟲清單或可供
討論的 mailing list,請告訴我該如何加入,我會在這兒提出的。]
========================================
Q139:為什麼我的 DOS C++ 程式說 "Sorry: floating point code not linked"
“抱歉,浮點運算程式碼未連結進來”?
編譯器會試著節省執行檔的大小,所以除非必要,否則不引入浮點數→字串格式轉換
的副程式,可是有時候它會猜錯,就會產生上述的錯誤訊息了。解決法:(1) 使用
而不要用 ,或是 (2) 在您程式的某個地方,置入如下的函
數(但是不要真的去呼叫它!):
static void dummyfloat(float *x) { float y; dummyfloat(&y); }
請參考關於 stream I/O 的 FAQ項目,有提到更多使用 vs
的理由。
========================================
Q140:為什麼當我沒執行 BC45 IDE 的話,BC++ 做出來的 Windows 應用程式就不能
用?
用 BC++ 寫 Windows 應用程式,如果當 BC45 IDE 正在執行時,你的程式很正常;
待會兒當 BC45 IDE 關掉了,而你的程式卻在建立視窗時產生了個 exception 的話
,就把底下這行程式加到你的應用程式類別 ("YourApp::InitMainWindow()") 裡頭
的 InitMainWindow() 內:
EnableBWCC(TRUE);
【譯註】這是因為你用 BC++ 寫的應用程式,可能會自動用到 bwcc*.dll,剛好
BC++ 的 IDE 也會用到它,所以兩者並存的話,BWCC 已先被 IDE 載入了。
若是 IDE 未執行,則 BWCC 未被載入,你就得用上面那一行程式來通知
OWL 去載入它。
== comp.lang.c++ FAQ 結束 =========================
|