2012年11月12日 星期一


近日攻擊變得稍多一些,可能跟下面三方漏洞齊出有關:

Adobe沙箱機制傳遭破解 PDF零時差攻擊蠢動
http://www.ithome.com.tw/itadm/article.php?c=77183

Android有簡訊詐欺漏洞?! 研究:所有版本均存在
http://www.nownews.com/2012/11/05/91-2869927.htm

微軟下周發布三個Win8危急級別安全補丁
http://news.cnyes.com/Content/20121109/KFNVZJQVWVKKB.shtml?c=detail
上週新聞,故本週出補丁;當中述及的IE 9漏洞其補丁應也是這週出吧
我沒用Win8 ,然而文中提的Technical debt 是微軟東東易受攻擊的主因之一

2012年10月21日 星期日


最近看到Intel還在打Fortran的廣告,覺得份外訝異,好奇心驅使下重拾這年近花甲的Fortran,
發覺果然進化很多,形式變美了,時下某些流行的演算法教本,拿Fortran來實作搞不好會比用C/C++等實作來得順手些。這或許是美國一堆大學還在教Fortran的原因

此處以 gfortran (i.e. GNU Fortran) 為主, 型式用free form

fixed form: 傳統用法即為固定型式
此型式範例: /usr/lib/python2.7/site-packages/wx-2.8-gtk2-unicode/wx/tools/Editra/tests/syntax/fortran_77.for

free form: 自由型式,從 Fortran 90 開始引進, 諸如GOTO, ASSIGN等影響結構化的傳統用法此型式皆禁用
此型式範例: /usr/lib/python2.7/site-packages/wx-2.8-gtk2-unicode/wx/tools/Editra/tests/syntax/fortran_95.f95
(上兩範例檔的套件版本 wxPythonGTK-2.8.12.0-5)

目前的 gfortran 版本(gcc-gfortran-4.6.1-3.3)對上面兩種型式可自動偵測與判斷;然同一程式兩型式不能混用
傳統上前5格(column)放陳述標號(statement label),第6格為續行標記,由於此處採用free form,為方便起見,通常程式每行前先按<tab>鍵
與以前相同,當續行標記有非0非空的其他字元,視為上一行之連續

注意大小寫同義,此與時下一般語言不同

程式由敘述(statement)組成,一行一敘述

ex.1 程式 hello.for 如下 ('!' 後接註釋)
! Hello World

        program HelloWorld              ! HelloWorld 為主程式名
            i = 100                   ! 與傳統類似,i~n六字母開頭的變數預設為整數變數,其他則預設為實數
            write (*,*) 'Hello, world!',i           ! =>  印出 Hello, world! 後接100  註:用雙引號亦可
        end program HelloWorld

上面程式以 gfortran -o hello hello.for 來編譯連結
=> 產生執行檔 hello  (若不加 -o hello 則預設執行檔為a.out)

若限定變數必先宣告方能使用,則於開始處加 implicit none

ex.2 印出 Hello! World! 後接列印次數,此例共印5次(一行一次)
        program HelloWorld5
          implicit none
          integer j                ! 宣告j為變數,其資料型態為整數 (因有上行implicit none,才須加此行)
          do j = 1, 5                       ! j為迴圈的控制變數(index),j將從1到5, i.e. 每作一次j會加1(預設)
            write (*,*) "Hello! World!",j
          end do                            ! 迴圈終點
        end program HelloWorld5

! 注意do迴圈內,控制變數不可重新定值(此與C語言等不同) 例如加一行 j=2 於此行前再編譯會產生錯誤

ex.3 結果"幾乎"同上(指含有Hello! World!的行同上例,但其後數字皆不是列印次數), 只是先將 "Hello! World!" 用parameter指定為常數名為h的字元常數
        program HelloWorld5a
          implicit none                            !  下行的parameter表設其為常數(i.e.不可更改)
          character*13, parameter :: h = "Hello! World!"    ! 一開始先宣告其為長度13之字元,其後
          integer :: k=9, i
          do i = 1, k, 2           ! 上行k定為9, 最後用2表以跳2方式來計數,故 i 依次為1 3 5 7 9
            if (i .eq. 3)  k=23             ! 當 i=3 時if條件為真,此時會對k重新定值為23,然入迴圈前上限已定,故此不會影響對迴圈的控制(與C等不同)
            if (i .eq. 5)  write (*,*) "現下 i=5"       ! 當 i=5 時if條件為真,此時會印出" 現下 i=5" (於第三行)
            write (*,*) h,i,k                      ! 除第一行k=9外,其他行有k的都會是23
          end do
          write (*,*) "在迴圈外:"
          write (*,*) "i= ",i         ! i超過迴圈上限(k=9)會跳出迴圈 => 此行的i會印出11
          write (*,*) "k= ",k         ! k為23
        end program HelloWorld5a

例中的 .eq. 為表"等於"之關係運算子(relational operator),其他的關係運算子如下:
.lt. 小於(<) .le. 小於或等於; .ne. 不等於;
.gt. 大於(>) .ge. 大於或等於

若ex.3例 if (i .eq. 3)  k=23 那行改成 if (i .eq. 5)  k=23   則可與其下行合併改寫為:
            if (i .eq. 5)  then
k=23
write (*,*) "現下 i=5"
            end if                        ! 此行寫成中間沒空格的 endif 亦可

ex.4 印出"Hello! World!" 後接i值 , 注意do迴圈雖開始於-9結束於-1, 然以2遞增,故do迴圈時i依次為-9,-7,-5,-3,-1 故仍是作5次
        program HelloWorld5b
          character h*5, w*6, x*13       ! 宣告三個字元變數h,w,x, 長度依次為5, 6, 13個字元
          data h,w/'Hello', 'World!'/    ! 可用data對變數設初值,此行使得 h = 'Hello' 且  w = 'World!'
                                         ! 若上行改成 data h,w/2*'Hello'/ 則 h 與 w 皆設成 Hello ;在重覆設值的情況可用 重覆次數*初值 來簡化
          x = h//'! '//w               ! 字元可用//(concatenation)來串接 =>  x = “Hello! World!”
          do i = -9, -1, 2             !
            if (i.eq.-9 .or. i.eq.-1)  print "('現下 i=-9 或 i=-1')"    ! 當i=-9或-1時,印出"現下 i=-9 或 i=-1" (i.e. 第一行跟倒數第二行)
            write (*,*) x, i                                            ! 上行加()是基於格式碼(後述)
          end do
        end program HelloWorld5b

例中 .or. 為 邏輯運算子,邏輯運算子如下(優先權順序有左至右, 而.eqv.與.neqv.優先權最低,但此兩者常相同):
.not. 非;  .and. 且;  .or. 或;
.eqv. 邏輯一致(coincidence);    .neqv. 互斥或(exclusive-or);與.eqv.互補,故.neqv.亦為邏輯不等
因 邏輯運算子的優先權 比 關係運算子 低, 故此if敘述的()中可不再額外加括號

字元變數名(或字元常數名)後可用(開始位置:結東位置)來截取 子字串, 底下以ex4為例:
x(1:5) = x(:5) = h = 'Hello'               ! 開始位置沒給時預設為1
x(8:13) = x(8:) = w = 'World!'             ! 結東位置沒給時預設到最後位置 (此例為13)
x(6:6) = '!'

優先權順序由大到小:(i.e.編號愈低者愈優先)
1.括號()  2.函數  3.次方**  4. 乘除*/  5.加減+-  6. concatenation //   7.關係運算子  8.邏輯運算子

gfortran 的邏輯.TRUE.與.FALSE.雖可分別與整數1與0轉換,
但不能與C語言等將整數用在if敘述中
且無論是邏輯或是整數,都不可像C般用在I/O運算上

ex.(註:雖可轉換,但編譯時會出現警告就是)
! ref.: 6.1.12 Implicitly convert `LOGICAL' and `INTEGER' values

      proGram var01
          implicit none
          LOGICAL k,l
          INTEGER  n
          k = .TRUE.                      ! 邏輯變數常規用法
          write (*,*) k                   ! 印T
          ! 由下可知 1 <-> .TRUE.
          l = 1
          write (*,*) l                   ! 印T
          if (l) write(*,*) "真"          ! 此行會印出"真"
          n = .TRUE.
          write (*,*) n                   ! 印1
          ! 由下可知 0 <-> .FALSE.
          l = 0
          write (*,*) l                   ! 印F
          if (l) write(*,*) "真"          ! 由於 l 為 .FALSE. 故此行不顯示
          n = .FALSE.
          write (*,*) n                   ! 印0
        end program var01


混型算式:
e.g. 此例算式為 整數/整數*實數  ;注意其並不會因最右數值為實數而一開始即全式以實數來計算,而是由運算順序逐步判定,故i/5仍是為整數運算的結果
        program mixTest1
          i = 2
          do while (i < 5)          ! 當do while後條件為真時皆在迴圈內,此例為 i = 2~4
            write (*,*) i/5*4.6     ! 由於i/5結果是整數 => 被除數小於5的皆為 0  故三次皆印出 0.0000000
            i = i+1              
          end do
        end program mixTest1

!  修訂只需改變次序轉成 i*4.6/5
! 當上行改成 i*4.6/5 後,由於電腦實數不符合數學上的實數調密性,故難精確,例如i=2時,將會印出 1.8399999

格式碼:(底下一對單引號可換成一對雙引號,反之亦然)
上例若須印得簡潔,則write那行改成 write (*,'(F4.2)') i*4.6/5   或者  print '(F4.2)', i*4.6/5 亦可,
其中 F4.2 表一實數印4格,其中2格為小數 (故整數只一格,因小數點亦另占一格) 此處 F 稱為格式碼
而用格式T可把資料印在自設的位置,如write那行改成 write (*,'(T10,F4.2)') i*4.6/5 表於第10格始印此實數
注意輸入時可省略小數點,例如 read (*,'(F5.2)') y  若執行時輸入1234 則存於y之值 實為 12.34;若輸入123則y成為1.23 (即以程式定的小數位數為主)
但若輸入時有加小數點,仍以輸入的小數位數為主,如對上行y輸入1.234,則實際上亦是存1.234

實數的格式碼尚有E, 但用E 會用科學表示法, 例如write那行改成 print '(E8.2)', i*4.6/5
E8.2 表共占8格,小數占2位,其後未顯示的小數部份會四捨五入,故會顯示如下:
0.18E+01
0.28E+01
輸入時省略小數點的情況類似F,例如對程式中有 read (*,'(E8.2)') x 執行時輸入123E3 因省略小數點,故依E格式所設的有兩小數,故實際成1.23E3 = 1230
但若輸入12.3E3 由於輸入時有加小數點,故以輸入為主,故實際上亦是存12300.  (注意輸入的指數部份只能整數;且有正負號時可省略E, 如1.6-1 = 1.6E-1 = 0.16)

而倍準度格式嗎D類似E,例如上面print的E8.2改成D8.2,則0.28E+01 會顯示成 0.28D+01

格式碼G會依照實際情況自動選擇 格式F 或 格式E
Gw.d 判斷原則:數值轉成科學表示法後,若 其指數>d 或指數為負,則選擇E;否則選格式F
ex.  write (*,'(G14.6)') 1234.56789   由於 1234.56789 = 0.123456789E4 而 4<6,故擇格式F => 印出 1234.57 (以科學表示之小數六位.123456為準)

其他較常用的格式碼尚有,I-整數,X-跳一格,A-字元資料,L-邏輯(T表真,F表假;輸入用開頭為T或F字串皆可<常用TURE或FALSE>,兩旁的.可加可不加)
以及用/格式來隔行,/的左右各代表不同行,例如 read (*,'(/F4.2/)') y  此時y於第二行輸入才有效,且後面尚空一行(第一,三行隨便打字亦不影響y值)

格式碼前的數字表此格式的重覆次數,例如:'(F4.2, 3X, F4.2)'  其中3X - 跳格X重覆3次,即表3個空格 故兩實數間有三空格
括號前加數數字亦有類次效果,例如:(2(3F4.2))' 相當於 '(2(F4.2, F4.2, F4.2))' 相當於 '(6F4.2)'

T格式尚有TR 與 TL,分別表從當前位置右移 與 左移,例如 TR3 表右移3格,故 TR3 與上面的 3X 同義,故 '(F4.2, TR3, F4.2)' = '(F4.2, 3X, F4.2)'
同理 TL3 表 左移三格;但注意輸入時以當前欲輸入的位置左移
例如 read (*,'(I4,TL3,I4)') i,j  若輸入123456 則i成1234後位置在5,以 TL3 往左移三格後位置在2,故j成2345 而6並未實際輸入至變數

為求方便,有些格式碼(如F,G,I,L等)後可緊接0, 此時程式會依照資料實際情況調格式大小,例如 '(F4.2)' 亦可改成 '(F0.2)';而'(L0)'相當於('L2')
然而字元資料若要如此則格式碼A後須不接數字。若A0則會因表字元寬度0而產生錯誤
例如 hello例的 ex4 的 write (*,*) x, i 那行若改成  write (*,'(A,T15,I1)') x, i   則印出的最後一行會為 "Hello! World! 9"

ex.5 印出5次 Hello! World!
        program HelloWorld5c
          character x*13
          x = "Hello! World!"            ! 下行(下下行)為implied do loop  (i=1~5,作5次)
!          write (*,*) (x, i = 1, 5)     ! 用此行輸出5個hello擠在一起
          write (*,'(A)') (x, i = 1, 5)  ! 用格式碼A才會分印五行的"Hello! World!"
        end program HelloWorld5c

! 最後write 那行亦可寫成 print '(A)', (x, i = -5,-1)    其實遞增1之五個整數數列皆可

另外可如ex.4般另加顯示字串於格式中,例如將ex.5的 '(A)' 改成 '("測試:"A)' 或 "('測試:'A)" 則會印出五行的 "測試:Hello! World!"


一維陣列:
預設元素最多僅能65535個,若超過則應於編譯時加參數 -fmax-array-constructor=元素個數
預設從1開始,故一般宣告陣列大小除為元素個外,常常也為註標(subscript)最大值; 如下例之i(n) 表陣列有 i(1),i(2)...i(n) 共n 個元素
ex. 印出一常陣列i,其元素為 2~200000 之偶數 (編譯方式:gfortran -fmax-array-constructor=100000 -o test ./test.for)
! ref. gfortran.info.xz

        program test
          integer, parameter :: n = 100000           ! 表 整數常數n 為 100000
          integer, parameter :: i(n) = (/ (2*j, j = 1, n) /)    ! 設陣列i, 其元素值依次為2,4,6,....200000
          print '(10(I0,1X))', i      ! I0 表依元素實際情況調整整數格式尺寸,其後接1空格,最先的10表一行印10個元素
        end program test

一般而言,若變數個數多於格式時,則其格式的原模式將重覆套於多出來的變數直至變數輸出(入)完成
然而若有內層括號,則以內層括號及其右邊為重覆模式套於多出來的變數,例如 (F4.2,2(X3,I5),X3,E8.2) 此時重覆模式為 (2(X3,I5),X3,E8.2)
對陣列亦同理,例中的陣列i雖100000個元素,但都是由10個元素的格式 (10(I0,1X)) 重覆套於陣列中所有的元素

印出部份陣列亦可用 implied do loop 代替,如只要印出50001~50100處,只需將print 那行改為:
print '(10(I0,1X))', (i(j), j = 50001, 50100)

若常陣列i改用變數陣列,則 integer, parameter :: i(n) = (/ (2*j, j = 1, n) /) 用下兩行代替:
dimension i(n)
i(:) = (/ (2*j, j = 1, n) /)
或用下列四行代替:
          dimension i(n)        ! 宣告陣列大小,開頭i即預設其元素為整數;  此行用 integer i(n) 亦可
          do  j = 1, n          ! 若陣列i未賦值,即此處省略以下三行,初值亂碼機率高,此點須注意
            i(j) = 2*j          ! 設陣列的元素值為陣列註標的兩倍
          end do
變數命名方式皆類似,故當陣列開頭不是i~n時亦不是預設為整數,若上面i(n) 改成a(n),則前頭須加一行integer a 方能用 dimension a(n)
故用 integer a(n) 會比用 dimension 方便

陣列宣告尺寸時可指定下限,例如把上面四行改成下面四行,則將陣列i 的尺寸設成僅從註標99991~100000 才十個元素:
          dimension i(99991:n)  ! 下限99991,表變數陣列i從99991開始;此行用 integer i(99991:n) 亦可
          do  j = 99991, n      ! 因上行只宣告99991~n ,故只能從 99991 開始賦值
            i(j) = 2*j
          end do
若是對例中的常陣列i 緊縮成這樣的十元素尺寸,僅需:
將          integer, parameter :: i(n) = (/ (2*j, j = 1, n) /)   此行
改成        integer, parameter :: i(99991:n) = (/ (2*j, j = 99991, n) /)  即可

因才十個元素,故編譯時可不加 -fmax-array-constructor=100000

陣列亦可再加allocatable宣告成動態配置,如下例:
ex.
! allocatable array 的元素個數即使100000 (超過65535個),編譯時也不必加  -fmax-array-constructor=100000
! ref.: gfortran.info.xz

        program test1alloc
          implicit none
          integer j,n
          integer, dimension(:), allocatable :: i
          n = 100000
          allocate(i(n))
          i(:) = (/ (2*j, j = 1, n) /)
          print '(10(I0,1X))', i
          deallocate(i)
          print "(//'deallocate(i)後可再重新配置, 輸入 n :')"
          read (*,"(I9)"), n
          allocate(i(n))
          i(:) = (/ (3*j, j = 1, n) /)
          print '(10(I0,1X))', i
          deallocate(i)
        end program test1alloc


陣列註標可為算式或者其他陣列的元素
ex.
! 拿陣列i元素值用在陣列j的註標上
! ref. gfortran.info.xz

      program test0c
          integer, parameter :: m = 99991, n = 100000
          integer, parameter :: i(m:n) = (/ (2*j, j = m, n) /)      ! 陣列i十元素同上,元素值為註標的兩倍
          dimension j(2*m:2*n)    ! 設 陣列j的註標上下限 各為 陣列i註標上下限 的兩倍;元素個數為2n-2m+1個 (此例為19個)
          do  k = i(m)/2, i(n)/2            ! 此行例與 do  k = m, n 同義;寫得較複雓只是為顯示這樣的寫法亦可
            j(i(k)) = 3*k         ! 注意陣列i的元素值成為陣列j的註標,故陣列j 僅偶數註標有以此行設到初值
          end do
          print '(10(I0,1X))', i      ! 下面印出結果的第一行
          print '(10(I0,1X))', j      ! 下面印出結果的二三行
        end program test0c

印出結果如下:(由於程式中僅對偶數註標的陣列j元素設初值,故奇數註標的陣列j元素皆為亂碼)
199982 199984 199986 199988 199990 199992 199994 199996 199998 200000
299973 -1215772392 299976 134519416 299979 -1215771952 299982 1 299985 0
299988 134519488 299991 -1217945612 299994 -1217087842 299997 -1215817072 300000

由上可知,GNU Fortran 的變數在已宣告定義卻尚未給初值前,其變數值為任意值
故最好在 dimension 下一行加一行data設初值,此映設例為加 data j/ 19*0 /
若要自動些,則改加一行為 data j/ p*0 /  且在n = 100000後加 ,p = 2*n-2*m+1 (p亦為常數,故p=...與n=...同行)
此時結果如下:
199982 199984 199986 199988 199990 199992 199994 199996 199998 200000
299973 0 299976 0 299979 0 299982 0 299985 0
299988 0 299991 0 299994 0 299997 0 300000

此例兩行print 合併為一行 print '(10(I0,1X))', i, j  亦會有相同的印出結果
這是由於陣列i恰有十個元素,印完陣列i後接印陣列j正好換行
但陣列i元素個數若不是10的倍數,則此行的接印會讓陣列i後部與陣列j前部印在同一行

若再將 print '(10(I0,1X))', i, j 改成  print '(3(10X,I0))', (k, i(k), j(2*k),  k = m, n)
依次為  陣列i的註標k  陣列i的元素i(k)  陣列j的元素j(2k)  (故陣列j中為0元素不會印出)


二維陣列:同矩陣,基於多維陣列於記憶體放置的方式,以矩陣A為列,當用data輸入A時,資料先填行;同理write等輸出A時,資料先輸出行
ex.
        program test3a
          implicit none
          integer, parameter :: n = 3
          integer a,i,j
          dimension a(n,n)
          data a/1,2,3,4,5,6,7,8,9/        ! 注意資料會先填行

          do  i = 1, n
            print '(3(I0,1X))', a(i,:)     ! 將陣列a第i列印出
          end do

          a = 1 + a             !此用法可使得加法運算皆用在陣列的每個元素上(四則運算皆適用)

          print '("每個元素都加1後:")'
          print '(3(I0,1X))', (a(i,:), i = 1,n)     ! 亦是將陣列a依列印出
        end program test3a
印出如下:
1 4 7
2 5 8
3 6 9
每個元素都加1後:
2 5 8
3 6 9
4 7 10

若希望先填列,可把data那行改成 data ((a(i,j), j=1,n), i=1,n)/1,2,3,4,5,6,7,8,9/


ex. 陣列a為 5x5大小,陣列元素依次為 1,2,3....25
        program test3
          implicit none
          integer, parameter :: n = 5
          integer a,i,j
          dimension a(n,n)
          do  i = 1, n                ! 巢狀迴圈
            do  j = 1, n
              a(i,j) = (i-1)*5+j      ! a(1,1)為1,a(1,2)為2,......a(5,5)=25
            end do
            ! a(i,:) = (/ ((i-1)*5+j ,j=1,n) /)     ! 上面三行可用此行代替
          end do

          print '(/A)', "印a: (用do loop 搭配 implied do)"
          do  i = 1, n
            print '(5(I0,1X))', a(i,:)
          end do

          print '(/"印a: (全用implied do loop)"/,5(I0,1X))',      ! 字數超過compiler限制,必須分行
     +                                         ((a(i,j), j=1,n), i=1,n)

          print '(/"不用loop而印a: (預設會先輸出行"
     ,",故陣列的行向量反而印成橫的)")'      ! 字數超過compiler限制,故必須分行
          print '(5(I0,1X))', a
          ! 即上行相當於 print '(5(I0,1X))', (a(:,j), j=1,n)    ! 依序印出第j行陣列

        end program test3

同理可推廣到多維陣列


副程式(subprogram):
函數(function)  與 副常式(subroutine)  為 Fortran 的 副程式(subprogram)
於其內定義的變數,可見性僅在函數內
注意Fortran為call by reference. 故計算結果亦可藉由parameter傳回,故parameter既可當輸入,又可當輸出,
若要明確規範某參數是輸入,則可於副程式內(或interface)的宣告parameter處加 intent(in)
若欲規範某參數是輸出,則可加 intent(out)
但這些多數情況並非強制,只為建立良好的程式習慣

函數:
函數可分三類 - 1. intrinsic func.(內存函數,又稱庫存函數)  2.statement func.(敘述函數) 3. 函數副程式(function subprogram)

intrinsic function: Fortran 提供的內建函數,例如sin(),cos()等三角函數;能得知陣列註標高低值的ubound(),lbound()...等

statement function: 自定函數可僅用單一敘述即完整地定義此函數
                    函數命名與變數命名類似,i~n六字母開頭的函數名預設其值域為整數,其他為實數

ex. 自定一敘述函數xor3(),對三個邏輯參數作互斥或(exclusive-or);並利用xor3()作出真值表
      proGram sfunc1
          LOGICAL i,j,k,l,m,n,xor3            ! 注意須先宣告xor3()回傳的資料型態為邏輯,不然函數值域會是實數(因xor3開頭為x)
          xor3(l,m,n) = l .neqv. m .neqv. n      ! 此行定義xor3();而l,m,n形式參數(formal parameter)亦可用i,j,k替代
          INTEGER x,y,z

          print *,"i j k XOR"          ! <=> write (*,*) "i j k XOR"
          do x = 0,1              ! 巢狀迴圈
            do y = 0,1
              do z = 0,1
                i = x             ! 將x,y,z中的整數0,1 轉成邏輯i,j,k
                j = y
                k = z
                print "(4L2)",i,j,k,xor3(i,j,k)         ! 此處為xor3()的實際應用,而括號內的i,j,k為實質參數(actual parameter, 實際參數)
              end do
            end do
          end do
      end program sfunc1

印出結果如下:  (輸出不含括號)
 i j k XOR     (x y z)
 F F F F       (0 0 0)
 F F T T       (0 0 1)
 F T F T       (0 1 0)
 F T T F       (0 1 1)
 T F F T       (1 0 0)
 T F T F       (1 0 1)
 T T F F       (1 1 0)
 T T T T       (1 1 1)

若須再例中再定義一個六參數的敘述函數xor6(),除最前宣告的LOGICAL::行中加 xor6 外,只需再於xor3()定義的下一行加:
xor6(i,j,k,l,m,n) = xor3(i,j,k) .neqv. xor3(l,m,n)
即可 (因 互斥或.neqv. 具結合性)

若定義函數的算式中有變數不在函數的引數中,則計算時會以在執行函數當時之變數值為準
例如上式若改定義成 xor6(l,m,n) = xor3(i,j,k) .neqv. xor3(l,m,n)
則執行xor6()時只需l,m,n三個引數,而看當時的i,j,k值為何再代入

函數副程式(function subprogram): 因函數有資料型態,故定義完後,亦須先宣告方能使用

ex.如上例,但以function subprogram來建立xor3()
      program sfunc1b
          implicit none
          INTEGER  x,y,z,xor3     ! 注意此例xor3()參數與回傳值皆是整數;而上例的是邏輯

          write (*,*) "x y z XOR"
          do x = 0,1
            do y = 0,1
              do z = 0,1
                 print "(4L2)",x,y,z,xor3(x,y,z)
              end do
            end do
          end do
      end program sfunc1b

      integer function xor3(x,y,z)
          integer, intent(in) :: x,y,z      ! 不加 intent(in) 雖也可,但規範是好習慣 (此處規範x,y,z當輸入)
          logical i,j,k,o
          i = mod(x,2)    ! mod()為庫存函數,用來取餘數,此例是對2取餘數
          j = mod(y,2)    ! 故此處偶數皆會取成0, 而奇數會取成1
          k = mod(z,2)
          o = i .neqv. j .neqv. k
          xor3 = o                ! 利用函數名xor3來回傳值
          return                  ! 此行return 可省略(因在最後一行)
      end function


ex. 計數器 (由此例知 函數亦可不需要參數)
      program tstcount0
          implicit none
          integer k, cnt                     ! 注意此 k 與 函數cnt()內之k 無關

          k = 100
          print "('1st time cnt() : ',I0)", cnt()
          print "('2nd time cnt() : ',I0)", cnt()
          print "('3rd time cnt() : ',I0)", cnt()
          print "('In main, k = ',I0)", k
      end program tstcount0

      integer function cnt()
          integer :: k = 0      ! 宣告行上的初始值只在第一次呼叫時設立
          k = k+1
          cnt = k
      end function

結果如下: (由結果易知 cnt() 的 k 變數 local & static)
1st time cnt(x) : 1
2nd time cnt(x) : 2
3rd time cnt(x) : 3
In main, k = 100

若cnt()中的k不要static, 只需將其宣告行改為 integer k = 0  (即省略 ::) 或者 integer k
如此則每次呼叫cnt()都只會回傳1 (當然最後一行結果仍是100)

當有參數等副程式漸複雜後,要於主程式使用它們須建介面
然可將函式用contains 含入主程式中,如此則可省去建interface步驟

ex. 可設值計數器 (預設參數例: 實際參數個數少於形式參數時,使用程設之內定)
      program tstcount00
          implicit none
          print "('1st time cnt() : ',I0)", cnt()
          print "('2nd time cnt() : ',I0)", cnt()
          print "('3rd time cnt() : ',I0)", cnt()
          print "('reset... cnt() : ',I0)", cnt(0)      ! 設計數器值為 0
          print "('cnt() recounting: ',I0)", cnt()
       contains
        integer function cnt(x)
          integer, intent(in), optional :: x     ! 宣告整數變數 x 為optional ,規範為輸入
          integer :: k = 0
          if (present(x)) then            ! present(): 測試呼叫此函式時,有無設用此參數,有用時為T,沒用時為F
                  k = x
          else
                 k = k+1
          end if
          cnt = k
        end function
      end program tstcount00

結果如下:
1st time cnt() : 1
2nd time cnt() : 2
3rd time cnt() : 3
reset... cnt() : 0
cnt() recounting: 1

若不用contains含入主程式中,則可implicit none 下行建一介面如下:
          interface
                  integer function cnt(x)
                          integer, intent(in), optional :: x
                  end function
          end interface


副常式(subroutine): 與函數類似,只是用call 來呼叫,且無回傳值 (但由於call by reference,故亦可如函數般利用參數來獲得計算結果)

`COMMON' blocks: 共享區設置,主程式與函數或副常式之間共用的區域
如今compiler由於最佳化等因素會自動alignment, 故共享區並不見得會如預想般的設置,
因此最好共享區中依物件尺寸由大到小的次序來設置
形式參數不可出現在它所屬副程式的common內
若想關閉 自動alignment,可在編譯時加 -fno-align-commons

ex.如函數xor3()例,此處改以subroutine建立,且搭配`COMMON' blocks,使call xor3 時不需參數,以`COMMON' blocks最後一變數為計算結果
      program sfunc1c
          implicit none
          INTEGER  k,l,m,n               ! 右說明下面的共用, 以'='表示共用相同區:k=x;l=y; m=z; n=x3
          common k,l,/testcom/m,n        ! /testcom/m,n 為具名common, 兩/之中的testcom為自設特定共同區之名 ;而k,l 為不具名common
                                         ! 注意同一common名可重覆出現,其後變數亦會依次放於此common名的共同區中
          write (*,*) "k l m XOR"
          do k = 0,1
            do l = 0,1
              do m = 0,1
                 call xor3               ! 此處呼叫副常式
                 print "(4L2)",k,l,m,n
              end do
            end do
          end do
      end program sfunc1c

      subroutine xor3()
          integer x,y,z,x3
          common /testcom/z,x3//x,y           ! // 表unnamed, 故//後為不具名common;有名者依名依次對應,不具名common依不具名區依次對應
          logical i,j,k,o
          i = mod(x,2)
          j = mod(y,2)
          k = mod(z,2)
          o = i .neqv. j .neqv. k
          x3 = o
 return          ! subroutine內最後的return亦可省略,如下例
      end subroutine


當要讓副程式的形式參數的陣列隨實質參數變動,則須建 interface

ex. 選擇排序法(排序之結果為遞增)
      program tstselection
          real :: y(100) = (/ (2*(101-j), j = 1, 100) /)   ! 設陣列j其元素依次為200,198,....,2
          interface
                  subroutine selection(a)
                    real  a(:)
                  end subroutine
          end interface
          print '(10(F0.0,1X))', y
          call selection(y)            ! 由於 call by reference, 故副常式執行完後改變陣列y
          write (*,*) "排序後"
          print '(10(F0.0,1X))', y
      end program tstselection

      subroutine selection(xa)           ! 排序,由小到大
          real xa(:)
          integer lb(1), ub(1)
          lb = lbound(xa)       ! Get bounds,  由於相容多維陣列,故回傳值亦為陣列
          ub = ubound(xa)       ! lb(1) 是得到一維陣列xa的註標下限,ub(1)是獲得註標上限
          do i = lb(1), ub(1)-1
            imin = i
            do j = i+1, ub(1)
              if (xa(imin) .gt. xa(j))   imin = j
            end do
            temp = xa(i)           ! swap
            xa(i) = xa(imin)
            xa(imin) = temp
          end do
      end subroutine

由於例中selection()的形式參數xa 並未固定其陣列尺寸(此例是隨實質參數y陣列而隨機調整xa),
故`COMMON' blocks不適用 (因common陣列必須先定尺寸,或在implicit情況下於common內定尺寸)


由於call by reference, 可將函數名或副常式名當reference參數用(此類參數若在interface中函式中出現,可仍以external宣告,如下面ex2r.例之II.法)
其有兩種宣告法:I.法 external (若是庫存函數只是external 改成 intrinsic,其他皆相同)  II.法 建立 interface

entry: 可在副常式或函數之中用entry加進入點(可不只加一個, 如下例中的 hello2與hello1)

ex1r.(藉參數傳遞副常式reference)
I.法 external
! hello3() 印 三次hello, hello2() 印二次,hello1()印一次
! 注意程式中是先把這些 hello副常式 作為 sayIt副常式的參數,主程式中是藉呼叫sayIt來達成這些動作的

      program hello4entry
          implicit none
          external hello3,hello2,hello1

          print *,"印三次hello"
          call sayIt(hello3)
          print *,"印兩次hello"
          call sayIt(hello2)
          print *,"印一次hello"
          call sayIt(hello1)
      end program hello4entry

      subroutine hello3()
          print *, "Hello! World!"
      entry hello2()                      ! 第一個entry
          print *, "Hello! World!"
      entry hello1()                      ! 第二個entry
          print *, "Hello! World!"
      end subroutine

      subroutine sayIt(fv)
        print *, "I say,"
        call fv
      end subroutine

II.法 Interface
把例中  external hello3,hello2,hello1   此行
改成
          interface
                  subroutine hello3()
                  end subroutine
                  subroutine hello2()      ! 注意 entry 在介面中不是以entry宣告,即就介面而言,視為另一個函數或副常式
                  end subroutine
                  subroutine hello1()
                  end subroutine
          end interface

ex2r. (上例的增改版)
I.法 external

      program hello4entry2
          implicit none
          external hello3,hello2,hello1,sayIt

          print *,"印三次hello"
          call doSomething(sayIt, hello3)
          print *,"印兩次hello"
          call doSomething(sayIt, hello2)
          print *,"印一次hello"
          call doSomething(sayIt, hello1)
      end program hello4entry2

      subroutine hello3()
          print *, "Hello! World!"
      entry hello2()
          print *, "Hello! World!"
      entry hello1()
          print *, "Hello! World!"
      end subroutine

      subroutine sayIt(fv)
        print *, "I say,"
        call fv
      end subroutine

      subroutine doSomething(fv1,fv2)    ! 雖然fv1與fv2對doSomething而言是形式是形式參數
        external fv2                     ! 但fv2 對 fv1 而言是實質參數,故此處須加external fv2
        print *, "I wanna do......"
        call fv1(fv2)
      end subroutine

II.法 Interface
把例中  external hello3,hello2,hello1,sayIt   此行
改成
          interface
                  subroutine sayIt(fv)
                     external fv          ! external 表其參數為函數或副常式
                  end subroutine
                  subroutine hello3()
                  end subroutine
                  subroutine hello2()
                  end subroutine
                  subroutine hello1()
                  end subroutine
          end interface

我們亦可將此段 interface 存成一個檔案,例如檔名為 hello4entry_i2b.intf
然後把 external hello3,hello2,hello1,sayIt 此行
換成   include "hello4entry_i2b.intf"  即可


遞迴:(使用時於編譯時加 -frecursive)
ex. 副常式遞迴例(階乘)
! e.g. gfortran -frecursive -o tstr1 tstr1.for

      program tstr1
          implicit none
          INTEGER  n, f
          interface
                  subroutine tstfact(n,f)     !   f = n!
                    integer n,f
                  end subroutine
          end interface

          n = 5
          call tstfact(n,f)
          print "('factorial ',I0,' is ',I0)", n ,f
      end program tstr1

      subroutine tstfact(n,p)
          integer n,p

          if (n .gt. 1) then
                  call tstfact(n-1, p)
                  p = n * p
          else
                  p = 1
          end if
      end subroutine


ex. 函式遞迴例,亦為階乘,效果同上,但為indirect recursion,故原一函式能處理的須複製成兩份交互遞迴
! e.g. gfortran -frecursive -o tstr0 tstr0.for

      program tstr0
          implicit none
          INTEGER  i
          interface
                  integer function fact0(n)     !    n!
                    integer n
                  end function
          end interface

          do i = 0,5    ! 從0! 印到 5!
            print "('factorial ',I0,' is ',I0)", i ,fact0(i)
          end do
      end program tstr0

      integer function fact0(n)
          integer n
          interface
                  integer function fact0b(n)
                    integer n
                  end function
          end interface

          if (n .gt. 1) then
                  fact0 = n * fact0b(n-1)
          else
                  fact0 = 1
          end if
      end function

      integer function fact0b(n)
          integer n
          interface
                  integer function fact0(n)
                    integer n
                  end function
          end interface

          if (n .gt. 1) then
                  fact0b = n * fact0(n-1)
          else
                  fact0b = 1
          end if
      end function


Cray pointers: (編譯時需加 -fcray-pointer 選項)
類似C語言的指標,此為non-standard extension
語法:pointer ( <pointer1> , <pointee1> ), ( <pointer2> , <pointee2> ), ...
亦可只宣告一對(<pointer1> , <pointee1> ) 其中 pointer1 為整數,表欲指向的記憶體位址;
而 pointee 類似被指對象之別名(alias),一般 pointee型態宣告應出現在指標宣告之後;需一對(pointer,pointee)互相搭配才會類似C的一指標
但若是用於 malloc() 則 pointee型態宣告 應出現在指標宣告之前
ex.
      program tst1pointer
          implicit none
          integer i
          real tar1(20)

          pointer(intp1, pte1(20))
          real pte1
          intp1 = loc(tar1)         ! 將指標與tar1連在一起,loc()函數類似C語言的&

          tar1(:) = (/ (i-21., i = 1,20) /)
          print "('original tar1 : '/, 10(F0.0,X))", tar1

          pte1(:) = (/ (i*10., i = 1,20) /)
          print "('tar1 changed by pointer : '/, 10(F0.0,X))", tar1
      end program tst1pointer

結果如下:
original tar1 :
-20. -19. -18. -17. -16. -15. -14. -13. -12. -11.
-10. -9. -8. -7. -6. -5. -4. -3. -2. -1.
tar1 changed by pointer :
10. 20. 30. 40. 50. 60. 70. 80. 90. 100.
110. 120. 130. 140. 150. 160. 170. 180. 190. 200.

注意!基於最佳化 pointee 的宣告最好不要如下用法,例如上例改成:
          real tar1(20)
          real pte1(20)

          pointer(intp1, pte1)
          intp1 = loc(tar1)
這種用法編譯器會過,但對Fotran來說是不合規則的(illegal)
因上面第二行已宣示pte1為大小20之實數陣列,其後竟將此已存在之實數陣列弄成指標
這種不合規則的用法編譯器不能保證程式執行的安全性

ex. malloc(), free()用法類似C
       program test2malloc
          implicit none
          integer i
          real*8 x(*)
          pointer(ptr_x,x)

          ptr_x = malloc(20*8)

          do i = 1, 20
            x(i) = i*10.
          end do

          print '(10(F0.0,3X))', (x(i), i = 1, 20)   !不能只用一x, 因x實非陣列, 故不像陣列般能知其尺寸

          call free(ptr_x)
       end program test2malloc



***其他補充***
equivalence(等位):
equivalence後同一括號內視為同一群,同一群中的變數共用記憶體,同一群的資料型態最好相同,適合會來作別名,及或多維陣列轉一維
ex. 底下 a,c是指同一個二維陣列,最後一行亦可改為 equivalence (a,b,c)
          integer a,i,j,b,c
          dimension a(3,3),b(9),c(3,3)
          equivalence (a,b),(b,c)
上面最後一行可改成 equivalence (a,b,c)
即 a,b,c 等位,注意先填列,如例中 b(2) 與 a(2,1) 及 c(2,1) 等位
當括號中有變數在common區時,則與其相連者皆在common;但在同一common區者必不能等位, 例如有common x,y則必不能equivalence (x,y)
且尚有些情況會產生錯誤,如例中假使其後再加一行 equivalence (j,b(3)),而其中尚有一行 common i,j,k ,則b照理應在共同區,
但是因連續放置問題...k,b(4)等位; j,b(3)等位; i,b(2)等位;...必然導致b(1) 超出共同區範圍,此會造成錯誤(在編譯時應就不會過)

亂數:
用法:call random_number(r)   r 可不限於一維陣列,r中元素即為亂數
亂數種子的副常式如例中 init_random_seed 般自設會較佳
ex.
      program tst1rand
          implicit none
          real :: r(5,5)
!          real :: r(100)
          integer i

          print "('before randome r: '/,5(F0.20,3X))", (r(i,:), i = 1,5)
          call init_random_seed()
          call random_number(r)
          print "('after randome r: '/,5(F0.20,3X))", (r(i,:), i = 1,5)
      end program tst1rand

      SUBROUTINE init_random_seed()              ! from: gfortran.info.xz
        INTEGER :: i, n, clock
        INTEGER, DIMENSION(:), ALLOCATABLE :: seed

        CALL RANDOM_SEED(size = n)
        ALLOCATE(seed(n))

        CALL SYSTEM_CLOCK(COUNT=clock)
        seed = clock + 37 * (/ (i - 1, i = 1, n) /)

        CALL RANDOM_SEED(PUT = seed)
        DEALLOCATE(seed)
      END SUBROUTINE


計算程式執行時間 (from: gfortran.info.xz)
ex.
          program test_cpu_time
              real :: start, finish
              call cpu_time(start)
                  ! put code to test here
              call cpu_time(finish)
              print '("Time = ",f6.3," seconds.")',finish-start
          end program test_cpu_time


2012年7月14日 星期六

google chrome 的亂連bug


由於家人懷疑電腦被駭,花了這幾天特別檢查了一下,
推測主因是這陣子網路連線品質變差應是受到hinet在作頻寬升級工程影響。
然而找問題的過程中發現google瀏覧器一開始執行時會先亂連三次,例如:
...... TCP_MISS/503 336 HEAD http://jfvxceosyw/ - HIER_NONE/- text/html
...... TCP_MISS/503 336 HEAD http://kctilgvwls/ - HIER_NONE/- text/html
...... TCP_MISS/503 336 HEAD http://hhdciljjve/ - HIER_NONE/- text/html

上面在chrome裡經過中文域名 Punycode 的轉換,
如上例第一行 jfvxceosyw 還原成 utf-8 為  旡日旘旨旝斵旙
而上例第二行 jfvxceosyw 還原成 utf-8 為  寅寑寍宻寉寃宿寎
其中 旡日旘旨旝斵旙  於utf-8 中的table    x6500 ~ x65FF 可找到
同理 寅寑寍宻寉寃宿寎 亦在x5B00~x5BFF 的table 上

只要能轉換成中文,皆會有如上述特徵,
雖然 hhdciljjve 不能轉成中文,但我相信在其他語言若能看到亦會有如上面類似的結果

實測不同版本的chrome皆有類似的問題,
不知道chrome 在開啟的過程中哪裡出了錯以致如此,
但應該不是被駭,因沒有非英文域名前綴xn--,
若能駭在高手如雲的駭客大賽中無法駭成功的chrome,
功力高到這麼深不可測,不應會漏掉前面要加xn--

但我想用純英文環境的系統應是沒有這樣的問題,
所以google沒發現有這個bug

2012年6月30日 星期六

我的電腦在潤秒


今天潤秒,由於潮汐力等導致地球自轉些微的不規律,與原子時鐘間產生誤差,故增潤秒來的校時

若你的電腦有裝 ntpd - Network Time Protocol (NTP) daemon 之類的軟體,
那麼在log上是看得到潤秒的痕跡的:

Jul  1 07:59:59 <我的電腦名稱> kernel: Clock: inserting leap second 23:59:60 UTC

基於與格林威治標準時的時差,故電腦在早上八點潤秒


今天是自1972年來第25次潤秒



關於潤秒的不錯文章:

http://big5.ce.cn/xwzx/shgj/gdxw/201206/29/t20120629_23448923.shtml
7月1日7時59分全球時間增1秒 閏秒去留引爭議

http://www.space.com/16356-leap-second-added-clocks-saturday.html
NASA explains why clocks will get an extra second on June 30

2012年6月27日 星期三

不曾璀燦的流星


眾人滿懷的希望  到來 意外的時間
諸神未貼實的星空 墜落 無聲無息

相信 未曾璀燦的流星
帶著原有的純淨
         昇華
            進入塵翅無法飛到的天堂

2012年6月3日 星期日

SWIG (Simplified Wrapper and Interface Generator)


SWIG (Simplified Wrapper and Interface Generator)
除能簡化 C/C++函式物件等在各語言間的使用,亦能達到相當程度的防駭功用
(因包裝後的程式碼已轉換,與原程式不同,故原碼即使有buffer overflow等弱點,轉換後弱點亦會消失)

swig預設輸出為當前目錄(i.e.相當於有一預設選項 -outcurrentdir),
可用 -outdir <目錄名> 或 -o [目錄名/]輸出wrap檔名 改變,
優先權為 -o  >  -outdir  >  -outcurrentdir

以 example.i , example.c 為例(其中example.i<自建>為example.c 的SWIG interface file)
example.c如下:
double  My_variable  = 3.0;

int  fact(int n) {
  if (n <= 1) return 1;
  else return n*fact(n-1);
}

int my_mod(int n, int m) {
  return(n % m);
}

一.
建一example.i如下:(底下的%module後接自定模組名而%{...%}的作用如同yacc或bison的%{...%})
%module example
%{
/* Put headers and other declarations here */
extern double My_variable;
extern int fact(int n);
extern int my_mod(int n, int m);
%}

extern double My_variable;
extern int fact(int n);
extern int my_mod(int n, int m);

I. 在tcl中用其C函式:(如沒tcl.h須先安裝libtcl-devel之rpm)
step 1. swig -tcl example.i                     ;=> 產生能給tcl用的 example_wrap.c
step 2. g++ -shared -fpic example.c example_wrap.c -o example.so
上會產生example.so
之後,打tclsh進入tcl後:
% load ./example.so ;=> 載入 example.so
% fact 5 ;=> 120 (i.e. 5!)
% my_mod 26 7 ;=> 餘5
% expr $My_variable + 5.5 ;=> 3.0+5.5 = 8.5

II. 在perl中用其C函式:(如沒EXTERN.h須先安裝perl-devel之rpm)(底下perl版本5.12.3, 不同者自改step2.)
step 1. swig -perl5 example.i     ;=> 產生能給perl用的example_wrap.c與example.pm
step 2. g++ -shared -fpic example.c example_wrap.c -I/usr/lib/perl5/5.12.3/i386-linux-thread-multi/CORE -o example.so
上會產生example.so
之後,建perl之script如下:(執行結果同I.)
#!/usr/bin/perl
# 下行即載入上面於同目錄下所建之example.so
use example;
print example::fact(5), "\n";
print example::my_mod(26,7), "\n";
print $example::My_variable + 5.5, "\n";        ;因此處example::My_variable為變數,故加$

III. 在python中用其C函式: (底下python版本2.7, 不同者自改step2.)
step 1. swig -python example.i     ;=> 產生能給python用的example_wrap.c與example.py
step 2. g++ -shared -fpic example.c example_wrap.c -I/usr/include/python2.7 -o _example.so
上會產生 _example.so
之後,建python之script如下:(執行結果同I.)
#!/usr/bin/python
# 下行即載入上面於同目錄下所建之_example.so (可視module example為物件)
import example
print example.fact(5)
print example.my_mod(26,7)
print example.cvar.My_variable + 5.5


二.簡化法:
step 0. 把 example.i 減化如下:
%module example
%{
#include "example.h"
%}
%include "example.h"

I.在perl中用其C函式(header files): (底下的example.h內容與example.c一模一樣)
step 1. swig -perl5 example.i ;=> 產生能給perl用的example_wrap.c與example.pm
step 2. g++ -shared -fpic example.h example_wrap.c -I/usr/lib/perl5/5.12.3/i386-linux-thread-multi/CORE -o example.so
上會產生example.so 之後步驟同 一II.

II.在php中用其C函式 (如沒php-config須先安裝 php-devel)
step 1. swig -php example.i ;=> 產生能給php用的example.php  example_wrap.c  php_example.h 三個檔案
step 2. g++ `php-config --includes` -shared -fpic example_wrap.c -o example.so
其中step1.會產生給php用的 example.php  example_wrap.cpp php_example.h 三個檔案
而step2.會產生example.so
之後,建一php script如下:(如沒/usr/bin/php須先安裝php-cli)
<?php
include("example.php");
echo fact(5) . "\n";
echo my_mod(26,7) . "\n";
echo example::My_variable_get() + 5.5 . "\n";
?>

且尚須在當前目錄下建一php.ini檔如右(僅一行): extension=./example.so
然後執行:php --php-ini ./php.ini ./ex_php        執行結果同一.


三.cmake  (底下以python為例)
一目錄中除有與一同example.i, example.cxx(亦與上述之example.c一模一樣)外,
尚須建一CMakeLists.txt檔案如下:
# 只需稍改後面四行即可用於其他的python程式
# 例如若是與二同之example.i與example.h 則把底下的example.cxx改成example.h

FIND_PACKAGE(SWIG REQUIRED)
INCLUDE(${SWIG_USE_FILE})

FIND_PACKAGE(PythonLibs)
INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_PATH})

INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})

SET(CMAKE_SWIG_FLAGS "")

SET_SOURCE_FILES_PROPERTIES(example.i PROPERTIES CPLUSPLUS ON)
SET_SOURCE_FILES_PROPERTIES(example.i PROPERTIES SWIG_FLAGS "-includeall")
SWIG_ADD_MODULE(example python example.i example.cxx)
SWIG_LINK_LIBRARIES(example ${PYTHON_LIBRARIES})

然後在此目錄下打: cmake .    (.表當前目錄)
其後再打:make
上會產生 _example.so  (若在Windows下會產生 _example.pyd)
其餘步驟同 一III.

四.c++ wrap (以python為例)(example.h與example.i同二.)(swig未完全支援c++,故預設為c)
(下面的step1產生能給python用的example.py與example_wrap.cpp<用-c++才可產生此.cpp,不然預設是.c>)
step 1. swig -c++ -python -o example_wrap.cpp example.i
step 2. g++ -shared -fpic example_wrap.cpp -I/usr/include/python2.7 -o _example.so
上會產生 _example.so 之後步驟同 一III.


五.於其他語言中使用C語言常用函式庫(以sin()與strcmp()為例)
建一檔example.h,把欲用到的函式其header files納進此檔,
由於我們這裡只用到sin()與strcmp(),故此處example.h內容只有下面兩行:
#include <math.h>
#include <strings.h>

而 example.i 如下:
%module example
%inline %{
#include "example.h"
extern double sin(double x);
extern int strcmp(const char *, const char *);
%}
#define PI 3.14159265359

I. 在tcl中用C函式:(如沒tcl.h須先安裝libtcl-devel之rpm)
step 1. swig -tcl example.i                     ;=> 產生能給tcl用的 example_wrap.c
step 2. g++ -shared -fpic example_wrap.c -o example.so
上會產生example.so
之後,打tclsh進入tcl後:
% load ./example.so ;=> 載入 example.so
% puts PI ;=> 輸出 3.14159265359
% sin [expr {$PI/2}] ;=> 輸出 1.0
% strcmp He He ;=> 輸出 0  (因兩字串相等)
% strcmp He She ;=> 輸出 -1 (因兩字串不相等)

II. 在python中用C函式: (底下python版本2.7, 不同者自改step2.)
step 1. swig -python example.i     ;=> 產生能給python用的example_wrap.c與example.py
step 2. g++ -shared -fpic example_wrap.c -I/usr/include/python2.7 -o _example.so
上會產生 _example.so
之後,建python之script如下:(執行結果同I.)
#!/usr/bin/python
# 下行即載入上面於同目錄下所建之 _example.so (可視module example為物件)
import example
print example.PI
print example.sin( example.PI / 2 )
print example.strcmp('He','He')
print example.strcmp('He','She')

III.在clisp中用C函式: (注意:step 2.可能因版本不同而需更改)
step 1. swig -clisp example.i     ;=> 產生能給clisp用的example.lisp
step 2. 在 example.lisp 中 的 (default-foreign-language :stdc) 之下增加一行:
        (setf +library-name+ "libstdc++.so.6")
        且為避免與clisp內建sin函數衝突,其下一行處之(ffi:def-call-out sin 的 sin 改成 sin2  
        然因(:name "sin") 保留沒更動,故仍以example:sin 方式呼叫之
之後,打clisp進入lisp後照以下進行,結果會同上:
(load "./example.lisp")
(print example:PI)
(example:sin (/ example:PI 2))        ;因clisp有內建PI, 故於此處...(/ PI 2)) 亦可
(example:strcmp "He" "He")
(example:strcmp "He" "She")


六.於其他語言中使用C++/C語言常用函式庫(以sin()與strcmp()為例)
example.h 與 example.i 同 五.

I.在Java中用C++/C函式: (注意:須先安裝java sdk, 而step 2.可能因java sdk版本不同而需更改)
下行會產生 exampleConstants.java  example.java  exampleJNI.java  example_wrap.cxx 四個檔案
step 1. swig -c++ -java example.i
step 2. g++ -shared -fpic example_wrap.cxx -I/usr/lib/jvm/java/include -I/usr/lib/jvm/java/include/linux -o example.so
上會產生 libexample.so
之後,建一java檔如下:(設檔名為runme.java)
public class runme {
  static {
    System.loadLibrary("example");
  }

  public static void main(String argv[]) {
    System.out.println(example.PI);
    System.out.println(example.sin(example.PI / 2));
    System.out.println(example.strcmp("He","He"));
    System.out.println(example.strcmp("He","She"));
  }
}

以 javac *.java 編譯成*.class後,再用 java runme 來執行,輸出結果同 五.

註:出現錯誤常是因為java.library.path中不含當前目錄,
    這時先export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH 後再跑java runme 即可


II.在Ruby中用C++/C函式:(如沒ruby.h須先安裝ruby-devel之rpm)(注意:step 2.可能因版本不同而需更改)
step 1. swig -c++ -ruby example.i           ;=> 產生能給Ruby用的 example_wrap.cxx
step 2. g++ -shared -fpic example_wrap.cxx -I/usr/lib/ruby/1.8/i586-linux/  -o example.so
上會產生example.so
之後,建一ruby程式檔如下:(執行結果同 五.)
#!/usr/bin/ruby -w
#下行即載入上面於同目錄下所建之example.so之module
require 'example'
puts Example::PI
puts Example.sin( Example::PI / 2 )
puts Example.strcmp('He','He')
puts Example.strcmp('He','She')


III.在Lua中用C++/C函式:(如沒lua.h等須先安裝liblua-devel之rpm)(注意:step 2.可能因版本不同而需更改)
step 1. swig -c++ -lua example.i           ;=> 產生能給Lua用的 example_wrap.cxx
step 2. g++ -shared -fpic example_wrap.cxx -o example.so
上會產生example.so
之後,建一lua程式檔如下:(執行結果同 五.)
#!/usr/bin/lua
-- 下行即載入上面於同目錄下所建之example.so之module
require "example"
print( example.PI )
print( example.sin( example.PI / 2) )
print( example.strcmp("He","He") )
print( example.strcmp("He","She") )


ref.
http://www.swig.org/tutorial.html
file:///usr/share/doc/swig/Manual/SWIGDocumentation.html
/usr/share/doc/swig-doc/Examples/ 中有不少其他語言的程式例