2010年6月6日 星期日

GCC (4.4.1)之C Preprocessor part II


這一篇主要是CPP manual第三章macro的心得,所以都是在講述macro。

object-like macro是最簡單的macro,就是直接將macro的name取代成code。
如:
#define NUMBER 1, \
               2, \
               3,
int x[] = {NUMBER}
 -> int x[] = { 1, 2 3 };
NUMBER會被展開誠1, 2, 3

當macro被展開之後,會再度的被檢驗是否還有macro需要被展開。
如:
#define TABLESIZE BUFSIZE
#define BUFSIZE 1024
TABLESIZE
 -> BUFSIZE
 -> 1024
TABLESIZE會先被展開成BUFSIZE,接著BUFSIZE再被展成1024。


Function-like macro用起來就像在用function,所以被稱為function-like macro。function-like macro是在macro name後面"緊"接括號。
如:
#define lang_init() c_init()
lang_init()
 -> c_init()

當macro name後面緊接著(),這個macro才會被當成function-like macro,否則會當成一般macro展開。
如:
extern void foo(void);
#define foo() boo()
....
 foo(); // macro
 funcptr = foo; // function

#define lang_init () c_init() // 多了空白在name和()之間
lang_init()
 -> () c_init()() // 結果就會造成錯誤


macro arguments,function macro可以像一般function一帶參數,這些參數會先被展開,接著再展開macro,參數要以","區隔開來(和一般的function一樣)。
如:
#define min(X, Y) ((X) < (Y) ? (X) : (Y))
x = min(a + 28, *p)
 -> x = ((a + 28), (*p) ? (a + 28) : (*p));
y = min(min(a, b), c)
 -> min(((a) < (b) ? (a) : (b)), c)
 -> .... // 產生的結果可能會和你想的不一樣


stringification(中文不知道怎麼稱呼,暫稱他字串化吧),當macro所帶的參數前面加上"#"之後,這個參數就會被展成字串,這就是stringification。
如:
#define WARN_IF(EXP) \
     do { if (EXP) \
             fprintf (stderr, "Warning: " #EXP "\n"); } \
     while (0)

WARN_IF (x == 0);
 -> do { if (x == 0) fprintf (stderr, "Warning: " "x == 0" "\n"); } while (0);

目前只有stringification,並沒有辦法轉成character。另外,stringification的優先權會高於argument expand。
如:
#define xstr(s) str(s)
#define str(s) #s
#define foo 4
str (foo)
 -> "foo"
xstr (foo)
 -> xstr (4)
 -> str (4)
 -> "4"


token concatenation或稱token pasting,是利用"##"將兩個token組成一個token,'##'被置於兩個token之間,如:
#define COMMAND(name) {#name, name ## _command}
struct command {
    char *name;
    void (*f)(void);
} cmds[] = {
    COMMAND(quit),
    COMMAND(help),
};
->
 struct command {
     char *name;
     void (*f)(void);
 } cmds[] = {
     {"quit", quit_command},
     {"help", help_command},
 };


variadic其實就是不定參數的function-like macro,__VA_ARGS__代表"..."(即後面所有的參數),如:
#define eprintf(...) fprintf(stderr, __VA_ARGS__)
eprintf("%s(#%d)\n", __FUNCTION__, __LINE__)
 -> fprintf(stderr, "%s(#%d)\n", __FUNCTION__, 7)

cpp也可以使用name取代__VA_ARGS__,用法上只是在"..."前面加上name,"_VA_ARGS__"則用name取代即可,如:
#define eprintf(args...) fprintf(stderr, args)
eprintf("%s(#%d)\n", __FUNCTION__, __LINE__)
 -> fprintf(stderr, "%s(#%d)\n", __FUNCTION__, 7)

來看另外一個例子
#define eprintf(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__)
eprintf("hello\n");
 -> fprintf(stderr, "hello\n", ); // error!!
這裡的問題就是如何將__VA_ARGS__前面的","在沒有參數帶入的時候刪除,答案就是"##"。
#define eprintf(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__)
eprintf("hello\n");
 -> fprintf(stderr, "hello\n"); // correct!!



2010年6月5日 星期六

gmake之4.8 Special Built-in Target Names - .PRECIOUS


4.8 Special Built-in Target Names - .PRECIOUS
The targets which .PRECIOUS depends on are given the following special treatment: if make is killed or interrupted during the execution of their commands, the target is not deleted. See Section 5.6 [Interrupting or Killing make], page 49. Also, if the target is an intermediate file, it will not be deleted after it is no longer needed, as is normally done. See Section 10.4 [Chains of Implicit Rules], page 107. In this latter respect it overlaps with the .SECONDARY special target. You can also list the target pattern of an implicit rule (such as ‘%.o’) as a prerequisite file of the special target .PRECIOUS to preserve intermediate files created by rules whose target patterns match that file’s name.

簡單的說就是當make在執行某個target的時候,如果make被kill或者被interrupted(ctrl+c),那麼target file就會被刪除,如果加到.PRECIOUS就不會刪除。

brook@ubuntu:~$ more Makefile
#.PRECIOUS: obj/x.o
obj/x.o:
        gcc -c x.c -o obj/x.o
        sleep 5;
brook@ubuntu:~$ make -f Makefile
gcc -c x.c -o obj/x.o
sleep 5;
^Cmake: *** Deleting file `obj/x.o'
make: *** [obj/x.o] Interrupt

brook@ubuntu1:~$ more Makefile
.PRECIOUS: obj/x.o
obj/x.o:
        gcc -c x.c -o obj/x.o
        sleep 5;
brook@ubuntu1:~$ make -f Makefile
gcc -c x.c -o obj/x.o
sleep 5;
^Cmake: *** [obj/x.o] Interrupt

brook@ubuntu1:~/excerise/Make$



2010年5月29日 星期六

TCL Basic Syntax


這一篇是研究所時候寫的,幸好還找的到,所以把它貼出來。

TCL (Tool Command Language),TCL念做"tickle",TCL本身不支援物件導向,但是可以和其他物件導向語言結合。

顯示字串到console用puts

variable

設定變數用set:

set varName? value?

set a 10
puts $a

事實上在Tcl中,沒有字串與數字的區分。也就是說:

        set Lab good

        set Lab “good”

這兩行指令會是一樣的結果。

 

comment

Tcl的注解必須以#開頭,而Tcl以換行(\n)和分號 (;)為命令的結束,所以如果想在命令後面做註解,就必須寫成 ;#。

puts "test only" ;# test only

 

data type

Tcl和shell script一樣並不需要是先宣告任何資料型態,其資料型態會隨其給的值變動。

 

Quotes and Curly braces

雙引號把引號內的文字串成字串,變數還是會被解譯(substitutions)。

set a "Hello World!"

 

"{", "}" curly braces,和雙引號一樣,只是變數不會被解釋。

set a "Hello World!"
puts "$a"
puts {$a}

 

"[", "]"就像shell中的`會把括號內的文字當成指令執行,而執行結果則會取代整個[]。

set x 5
set y 10
set z "$x + $y is [expr $x + $y]"

 

另外backslash "\",會讓substitutions失效,如同其他language一樣,tcl也有提供Backslash Sequence。

String Output
\b   Backspace
\f   clear screen
\n   New Line
\r   Carriage Return
\t   Tab
\v   Vertical Tab

 

Control

if  {expr1} {body1} elseif {expr2} {body2} else {body}

set x 1
 
if {$x == 2} {
       puts "$x is 2"
} else {
       puts "$x is not 2"
}
 
if {$x != 1} {
       puts "$x is != 1"
} else {
       puts "$x is 1"
}

 

switch

Evaluate one of several scripts, depending on a given value

switch ?option? string {body}

% set x 1
1
% switch $x {
1 {puts "match 1"}
2 {puts "match 2"}
default {puts "no match"}
}
;# match 1  --> result

 

% set x 10
10
% switch $x {
1 {puts "match 1"}
2 {puts "match 2"}
default {puts "no match"}
}
# no match ---> result
% switch -regexp $x {
1 {puts "match 1"}
2 {puts "match 2"}
default {puts "no match"}
}
# match 1 ---> result

 

loop

while {test} {body}

set x 0
while {$x < 5} {
     set x [expr $x + 1]
     if {$x > 7} break
     if "$x > 3" continue
     puts "x is $x"
}

 

for {start} {test} {next} {body}

for {set x 1} {$x < 10} {incr x 2} {
     puts "x = $x"
}

 

新增命令 -- procedure

TCL可以使用proc建立一個新的命令,其格式如下。

proc name { args }  {
     body
}

proc會建立一個名為name的命令,並且攜帶參數args,以及程式碼body。如果最後一個參數名稱為args,那就類似C的不定參數"..."。

範例:

proc sum {arg1 arg2} {
    set x [expr {$arg1 + $arg2}];
    return $x
}

proc printall {args} {
    foreach j $args {
        puts "$j"
    }
}

proc x {a {b 2}} { #give default vaule for b
    puts $a
    puts $b
}

 

Associative Array

associative array其實就是hash table,給一個Key(Tcl稱為element)會傳回一個value。其範例如下:

set A(1) "one"
set A(2) "two"
set A(Three) "three"
array set B { 1 "one" 2 "two" 3 "three" }
 
array names A
foreach thing [array names A] {
   puts "$A($thing)"
}

 

array set arrayName list

建立陣列,list 必須以 key value形式組成。

 

array size arrayName

傳回陣列大小。

 

array names arrayName ?mode? ?pattern?

 如果只有array names arrayName將會回傳所有的key,否則您也可以用正規表示式搜尋key是否存在。

 

array unset arrayName ?pattern?

如果沒有指明pattern,會將整個array註銷,否則會比對pattern和key是否相同,如果有會註銷該元素 (key),否則會回傳空字串(empty string)。

 

array exists arrayName

如果陣列存在會回傳1,否則會回傳0。

 

array get arrayName ?pattern?

如果沒有指明pattern會將array整個以key value的形式傳回。如果有指明pattern則會搜尋是否有符合的key,有的話會一樣以key value傳回,否則傳回空字串。

 

array statistics arrayName

會將array的資訊顯示出來(distribution of data within the hash table)。

 

array startsearch arrayName

這是用來初始化搜尋的指令,會回傳search-ID,可用於array nextelementarray donesearch指令。

 

array nextelement arrayName searchId

傳回array的key。如果array被新增或刪除,則Tcl會自動呼叫array donesearch終止目前的搜尋。

 

array donesearch arrayName searchId

終止array的搜尋,並且註銷array的search-ID。

 

array anymore arrayName searchId

 

 

更多的tcl tutorial(tcl8.5)

 


熱門文章