Provided by:
manpages-zh_1.5.1-1_all 
NAME
Tcl_NewObj, Tcl_DuplicateObj, Tcl_IncrRefCount, Tcl_DecrRefCount,
Tcl_IsShared, Tcl_InvalidateStringRep - 操縱 Tcl 對象
` SYNOPSIS
#include <tcl.h>
Tcl_Obj *
Tcl_NewObj()
Tcl_Obj *
Tcl_DuplicateObj(objPtr)
Tcl_IncrRefCount(objPtr)
Tcl_DecrRefCount(objPtr)
int
Tcl_IsShared(objPtr)
Tcl_InvalidateStringRep(objPtr)
ARGUMENTS
Tcl_Obj *objPtr (in) 指向一蚢龠H;必須是以前調用 Tcl_NewObj
返回的結果。
_________________________________________________________________
INTRODUCTION
這茪漭U韌ㄗ悀F對 Tcl 對象以及如何使用它怐漱@虓囫。它還描z了管理 Tcl
對象的一些一般過程。使用這些過程來建立和複製對象,和增加和減少到對象的引用(指針)-
p數。這些過程與那些在特定類型的對象如 Tcl_GetIntFromObj 和
Tcl_ListObjAppendElement 上進行操作的過程聯合使用。單獨的過程和它-
怍瓴瓾a的數據結構被放在一起描z。
Tcl 的雙端口(dual-ported)對象為存儲和交換 Tcl ㄗ悀F一茬q用的機制。它-
怞b很大程度上替代了 Tcl 中字符串的使用。例如,它抭Q用來存儲變量-
B命令參數、命令結果、和稿本。Tcl
對象外在表現很像字符串,但它還持有可以被更加有效的操縱的內部表示。例如,現在一-
Tcl 列表被表示為持有列表的字符串表示的一蚢龠H,如同到每-
茼C表元素的指針的一蚍捸C雙端口對象避免了運行時的類型轉換。它-
攽棷ㄟ炊F釵h操作的速度,鴞]是可以立即獲得一蚞A當的表示。編譯器自豕洏
Tcl 對象來緩存(cache)作為編譯稿本的結果的字節碼指令。
這兩種表示互為緩存並且被以懶惰方式p算。就是說,每茠磳亶ㄔu在需n時才被-
p算,它被從另一種表示p算出來,而一旦被-
p算出來了,它就被保存起來。除此之外,其中一茠磳靰漣幭亃N使另一-
茠磳雃足做L效 。舉茖狺l,一荌翔蒱B算的 Tcl 程式可以在一-
蚥僆q的內部機器整數表示上進行直接操作,而不需-
n經常性的在整數和字符串之間進行轉換。只有在需n這蚥僆q的漱@-
茼r符串表示的時唌A比如列印它,程式才奐s生成這-
蚞蒱漲r符串表示。儘管對象包含一茪熙〞磳隉A但它-
怐獄y義仍是依據字符串定義的:
總是可以獲取最新的字符串,在取回對象的字符串表示的時-
唌A對對象的任何改變都將反映到取回的那茼r符串上。因為這-
茠磳頇O無效的並被奐s生成了,擴展作者直接訪問 Tcl_Obj
的字段是很危險的。最好使用 Tcl_GetStringFromObj 和 Tcl_GetString
這樣的過程來訪問 Tcl_Obj 信息。
在堆上分配對象,使用到它怐 Tcl_Obj 結構的指針引用對象。對象-
n盡可能的共享。這將顯著的縮減存儲需求,-
鴞]是一些對象比如長列表是非常大的。還有,多數 Tcl u是被讀而從不被-
蚹鵅C尤其是過程參數,它怚i以在調用和被調用的過程之間共享。賦-
M參數綁定是通過簡單的賦予到這蚧的一茷針完成的。使用引用-
p數來確定什麼時堎k還一蚢龠H的存儲是安全的。
Tcl 對象是有類型的(typed)。一蚢龠H的內部表示由它自己的類型來控制。在
Tcl
核心中預定義了七種類型,其中包括:整數、雙精度浮點數、列表、和字節碼。擴展作者可是使用
Tcl_RegisterObjType 過程來擴展類型的集合。
Hc THE TCL_OBJ STRUCTURE
每 Tcl 對象都被表示為一 Tcl_Obj 結構,其定義如下。
typedef struct Tcl_Obj {
int refCount;
char *bytes;
int length;
Tcl_ObjType *typePtr;
union {
long longValue;
double doubleValue;
VOID *otherValuePtr;
struct {
VOID *ptr1;
VOID *ptr2;
} twoPtrValue;
} internalRep;
} Tcl_Obj;
bytes 和 length 成一起持有一蚢龠H的字符串表示,這是一茪wp數的
(counted) 字符串或二進制串 (binary string),二進制串可能包含有嵌入的
null 字節的二進制串。bytes 指向這茼r符串表示的第一茼r節。length 成-
給出字節數。字節數組的在偏移量 length 上,也就是最後一茼r節後-
悼眸溥`是有一 null;這允酗ㄔ]含 null 的字符串表示被作為一荓`規的用
null 終結的 C 語言字符串來對待。 C 程式使用 Tcl_GetStringFromObj 和
Tcl_GetString 來得到一蚢龠H的字符串表示。如果 bytes 是
NULL,則字符串表示無效。
一蚢龠H的類型管理它的內部表示。成 typePtr 指向描z類型的 Tcl_ObjType
結構。如果 typePtr is 是 NULL,則內部表示無效。
internalRep 聯合成持有一蚢龠H的內部表示。它可以是一(長)整數,一-
蚋戇諞蚽B點數,或者一茷針、它指向包含這蚚型的對象n表示對象所需-
n的補充信息的A或者是兩茈艩N的指針。
使用 refCount 成來通告在什麼時堐孺韙@蚢龠H的存儲是安全的。它持有到這-
蚢龠H的活躍引用的p數。維護正確的引用p數是擴展作者的一-
蚚鶬銎坁熙d任。在下悸犒龠H的存儲管理 (STORAGE MANAGEMENT OF OBJECTS)
章節中討論了引用p數。
儘管擴展的作者可以直接訪問一 Tcl_Obj 結構的成-
,但最好還是使用恰當的過程和宏。例如,擴展作者永遠不n直接讀或蚹
refCount;作為替代,他抸雪磻洏庣 Tcl_IncrRefCount 和 Tcl_IsShared
這樣的宏。
Tcl 對象的一蚚鶬鞂搣坌O它持有兩茠磳隉C典型的,一蚢龠H開始時只包含一-
茼r符串表示: 它是無類型的並且typePtr 是一 NULL。分別使用 Tcl_NewObj 或
Tcl_NewStringObj 建立包含一茠臟磢漱@蚢龠H或一茷定字符串的一荋_件。一-
蚢龠H的字符串i以使用 Tcl_GetStringFromObj 或 Tcl_GetString
來獲取並使用 Tcl_SetStringObj 來改變它。如果如果這蚢龠H以後被傳遞給像
Tcl_GetIntFromObj 這樣的n求一荅S定的內部表示的過程,則這蚢L程將建立一-
茪熙〞磳雰籀]置這蚢龠H的 typePtr。從字符串表示來p算它的內部表示。一-
蚢龠H的兩茠磳頇O雙囿: 對一茠漣幭雂]將反映到另一-
茪W。例如,Tcl_ListObjReplace 將蚹鴾@蚢龠H的內部表示,下一茖
Tcl_GetStringFromObj 或 Tcl_GetString 的調用將反映這荍幭隉C
出於效率的鴞]以懶惰方式厚算表示。一蚢L程如 Tcl_ListObjReplace 對一-
茠磳靰漣幭雂ㄔ艂Y反映到另一茠磳雂W。作為替代,把另一-
茠磳僂訄O為無效,如果以後需n的話再奐s生成。多數 C 程式-
永遠無須關心這是如何完成的,他怚u是簡單的使用像 Tcl_GetBooleanFromObj
或 Tcl_ListObjIndex 這樣的過程。而實現自己的對象類型的程式-
必須檢查無效表示和在需n時標記一茠磳頇做L效。使用過程
Tcl_InvalidateStringRep 來標記一蚢龠H的字符串表示為無效並釋放與這-
茼r符串表示相關聯的存儲。
對象在它的一生當中通常保持一種類型,但是有時一-
蚢龠H必須從一種類型轉換成另一種類型。例如,一 C 程式可以通過契_調用
Tcl_AppendToObj 來在一蚢龠H中建造一茼r符串,並接著調用 Tcl_ListObjIndex
來從一蚢龠H中提取一茼C表元素。持有相同字符串的同樣的對象在不同的時-
唹i能有多種不同的內部表示。擴展作者可以使用 Tcl_ConvertToType
過程強制把一蚢龠H從一種類型轉換成另一種類型。只有建立新對象類型的程式-
才需n關心這是如何作的。作為對象類型實現的一部分,需n定義為一-
蚢龠H建立一虓s的內部表示和改變它 typePtr 的一蚢L程。如何建立一-
虓s對象類型請參見 Tcl_RegisterObjType 手冊間C
HRP EXAMPLE OF THE LIFETIME OF AN OBJECT
作為一蚢龠H生命周期的一茖狺l,考慮下列命令序列:
set x 123
這裏把一茈憚壅型的對象賦 x,這蚢龠H的 bytes 成指向 123 而 length
成包含 3。對象的 typePtr 成是 NULL。
puts "x is $x"
x 的字符表示是有效的(因為 bytes 是非 NULL)並被這茤R令取回。
incr x
incr 命令漸通過調用 Tcl_GetIntFromObj 從 x (所引用的)的對象的得到一-
蚞蒱C這蚢L程檢查這蚢龠H是否已經是一蚞蒱龠H。由於它不是,就通過把這-
蚢龠H的 internalRep.longValue 成設置為整數 123,並把這蚢龠H的 typePtr
設置為指向整數的 Tcl_ObjType 結構,此過程把這蚢龠H轉換成了整數對象。兩-
茠磳亄{在都是有效的。incr 增加這-
蚢龠H的整數內部表示,接著使它的字符串表示無效(通過調用
Tcl_InvalidateStringRep),鴞]是這茼r符串表示不再與內部表示相對應了。
puts "x is now $x"
現在需n x (所引用的)的對象的字符串表示,n奐sp算它。字符串表示現在是
124。兩茠磳雂S都是有效的了。
Hsxz STORAGE MANAGEMENT OF OBJECTS
Tcl 對象在堆上分配,並且n盡可能的共享對象來縮減存儲需求。使用引用-
p數來確定何時一蚢龠H不再被需n並可以被安全的釋放。镼 Tcl_NewObj 或
Tcl_NewStringObj 建立的對象的 refCount 是 0。當建立到這蚢龠H的一-
虓s引用時,使用宏 Tcl_IncrRefCount 增加引用p數。當不再需n一茪犍峈漁尕
,使用 Tcl_DecrRefCount 減少引用p數,而且如果這蚢龠H的引用p數下-
馬儦s,就釋放它的存儲。被不同的代碼或數據結構共享的一蚢龠H的 refCount
大於 1。增加一蚢龠H的引用p數來確保它不會被過汛孺顑峈怚扛-
Q意外的改變。
舉-
茖狺l,字節碼解釋器在調用者和被調用的過程之間共享參數對象,以避免複製對象。它把調用者的實際參數的對象賦-
凳L程的形式參數變量。此時,它調用 Tcl_IncrRefCount 來增加每-
蚢篕痚捊(所引用的)的對象的引用p數,鴞]是有了從形式參數到這蚢龠H的一-
虓s引用。在被調用的過程返回的時唌A解釋器調用 Tcl_DecrRefCount 來減少每-
荌捊漱犍姩數。當一蚢龠H的引用下馬鴗p於等於零的時唌A Tcl_DecrRefCount
歸還它的存儲。多數命令過程不是必須關心引用p數的,鴞]是它怚艂Y使用一-
蚢龠H的疇B在它怐藀^之後不保留到這蚢龠H的指針。但是,如果它怬漼鴗@-
蚢龠H的指針保留到一蚍痤硎c中,則他怚眸楫`意n增加它的引用p數,鴞]是這-
茷O留的指針是一虓s引用。
像 lappend 和 linsert 這樣的直接蚹儮龠H的命令過程必須注意n在蚹鴾@-
茼@享的對象之前複製它。 他怚眸滓先調用 Tcl_IsShared 來檢查這-
蚢龠H是否是共享的。如果對象是共享的,則他怚眸楊洏 Tcl_DuplicateObj
複製這蚢龠H;它返回鴝l對象的一虓s複製品,其 refCount 是
0。如果對象未被共享,則命令過程「擁有」這蚢龠H並可以安全的直接-
蚹鴷式C例如,下列代碼出現在實現 linsert 的命令過程當中。通過在 index
的前探﹞J objc-3 新元素,這蚢L程蚹鵀b objv[1] 中傳遞給它的列表對象 。
listPtr = objv[1];
if (Tcl_IsShared(listPtr)) {
listPtr = Tcl_DuplicateObj(listPtr);
}
result = Tcl_ListObjReplace(interp, listPtr, index, 0, (objc-3), &(objv[3]));
另一茖狺l,incr
的命令過程在增加變量(所引用的)對象內部表示中的整數之前,必須檢查這-
蚥僆q(所引用的)對象是否是共享的。如果它是共享的,則需n複製這-
蚢龠H,目的是避免意外的改變在其他數據結構中C
SEE ALSO
Tcl_ConvertToType, Tcl_GetIntFromObj, Tcl_ListObjAppendElement,
Tcl_ListObjIndex, Tcl_ListObjReplace, Tcl_RegisterObjType
r KEYWORDS
internal representation, object, object creation, object type,
reference counting, string representation, type conversion
[]
Hhh
[]
2001/10/30
m Linux manUpn:
http://cmpp.linuxforum.net