2018年5月17日 星期四

[自助日本行 1/5] 20180406 台灣 -> 成田空港 (NEX) -> 東京 -> 上野

日期: 20180406
地點: 台灣 - 東京 - 上野
這次的日本行共 5 天, 20180406 ~ 20180410。
人數: 2
花費:
MYSTAYS 飯店 - 上野東 (HOTEL MYSTAYS Ueno East, 5-5-6 Higashi-Ueno Taito-ku 東京 日本 110-0015: 14556+218

機票:
2018/04/06 ~ 2018/04/10
點數  2018/01/26 完成付款 TWD 120
信用卡  2018/01/26 完成付款 TWD 32,530
總額 TWD 32,650



一樣搭乘香草航空, 不過這次的機票錢貴很多, 我後來才知道是日本櫻花季 (四月) 的關係, 真冤枉, 我沒想看櫻花阿!

這次目標設定在搭乘新幹線, 日本吸引我的就是鐵路, 但我並非鐵道迷, 但台灣的鐵路實在單調, 去日本才有辦法享受這麼複雜的鐵路系統。

有個很興奮的人找了省錢的辦法, 購買 JR pass, 我本來只是想搞懂怎麼買票, 直接買就好, 不過 JR pass 為我們這次的旅行省下不少錢, 某人功勞不小。

計劃是這樣:
購入 JR 東京廣域周遊券, JR pass 好幾種, 這種適合我們 5 天的旅程。
JR pass 不是想像的那樣, 可以搭乘所有車種, 請到 JR 網站查詢, 有繁體中文, 資訊很豐富, 其實不太需要看別人的文章, 沒有比官網更正確的資料了。

JR 東京廣域周遊券不能搭乘隼號和小町號, 如果你沒事先知道, 又剛好定了這 2 台車, 櫃台人員應該會跟你說不能搭乘, 可是由於語言問題, 你一定會在這問題上卡很久, 搞不清楚為什麼不能搭乘, 甚至影響後續計劃。

JR 東京廣域周遊券可以搭乘的新幹線路線有:
  1. 北陸新幹線
  2. 上越新幹線
  3. 東北新幹線
我們這次就是搭乘了:
  1. 北陸新幹線
  2. 東北新幹線
由於可以用 3 天, 所以這麼計劃:
day 1: 搭乘 NEX 從成田空港到上野。
day 2: 輕井澤
day 3: 小山

這樣就把 JR 東京廣域周遊券用到極致了。

到成田空港之後, 一樣到走路到第二航廈, 找到了 fig 1 的 JR 旅行務中心, 在地下一樓, 只要沿著「鐵道」的標誌尋找應該就找得到, 上次我一個人來就是這樣找到的, 大家應該也都沒問題的。

fig 1. 成田空港 JR 旅行服務中心

成田空港的 JR 旅行服務中心不是綠色的, 而是紅色的, 真是奇怪。裡頭遊客真的很多, 應該都是要來買 JR PASS, 得要花點時間等待, 我們運氣還不錯, 大概在這裡耗掉半小時左右。

要購買 JR pass, 最好也事先查好要搭乘的火車車種、時間、出發車站、目的地車站。

以 NEX 為例子:
車種: NEX
時間: 14:48
出發車站: 成田空港第二航廈
目的地車站: 東京

fig 2. JR 時刻表

這是某人查的, 我輕鬆的跟著搭乘就好了, 真的感謝她, 所以其實我不知道怎麼查詢這些資訊, 不過我後來買了一本 JR 時刻表, 上面就有這些資訊了 (fig 2), 所以我還是知道要怎麼查的。

第二天的輕井澤新幹線也順便一起劃位:
車種: hakutaka 555
時間: 08:50
出發車站: 上野
目的地車站: 輕井澤

fig 3. JR 東京廣域周遊券與劃位好的 NEX 車票

第一次買 JR pass 不熟, 又遇到新手櫃台人員, 我們搞了好久才買好, 也讓不熟悉這個業務的雙方, 彼此有喘息的機會, 不會搞得太緊張。不熟, 能慢慢來是最好的。

到我們住宿的上野其實搭乘 skyliner 比較方便, 不過買了 JR PASS 之後, 可以免費搭乘 NEX, 不用白不用, NEX 要 2000 日元, 我們買的 JR 東京廣域周遊券要價 10000 日元。

fig 3 就是購買的 JR 東京廣域周遊券和劃位的車票。加上第二天要搭乘的新幹線, 就已經賺回來了。



NEX 到上野需要轉車, 到東京之後再轉山手線到 JR 上野, 不過不急著去山手線, 先來看看 NEX 分離的有趣行為。

有的 NEX 班次會在東京分離, 變成 2 輛獨立行駛的火車, 我們搭的這台就是這樣, 所以特地在這裡等待其分離。


在這裡耽擱了不少時間, 這是自由行的好處, 可以隨意的調整自己的步調, 愛幹麻就幹麻, 我就是想看 NEX 分離嘛!

這是我第一次來到 JR 東京車站, 果然很大, 沿著路標走了不少路, 終於來到山手線了, 仔細看好方向, 搭錯邊就要繞遠路了。山手線在我上次的旅行中已經搭乘過, 沒有陌生感, 非常的順利就抵達 JR 上野車站, 出站時先看看我們明天要去搭乘的新幹線入口, 明天就是要從這裡進去搭乘新幹線。

飯店浴缸


本來要從上野走路到 MYSTAYS 飯店, 不過有人發現 tokyo metro 的稻荷町車站離飯店更近, 所以我們就搭乘 tokyo metro 的銀座線, 從銀座線的上野車站到稻荷町車站, 而運氣很好的是, 銀座線的上野車站就在 JR 上野車站裡頭, 只是路程有點蜿蜒, 距離有點遠, 上下坡有點多, 就這樣, 繞了老半天, 終於走到銀座線的上野車站, 往淺草方向的月台搭乘, 第一站就是稻荷町車站。

到稻荷町車站已經下午五點多, 看著 google map 找到方向之後, 往 MYSTAYS 飯店走去, 途中出了點差錯, 不過不礙事, 很容易就找了飯店了。

房間真的很小, 被一張雙人床佔據大部分空間之後, 幾乎沒什麼可移動的空間, 連行李箱都無法正常打開, 但是在這麼小的房間中, 廁所還是有個浴缸, 台灣的飯店幾乎都為了省空間而很少有浴缸, 日本人看來對浴缸很重視, 我也偏愛有浴缸的設施, 往後每天我幾乎都會泡澡, 這可是難得的休閒。

休息整理行李之後, 準備外食, 享受來日本的第一個晚餐, 一樣搭乘銀座線抵達上野廣小路車站, 這裡出了一點小差錯, 如果有搭過高雄橘線捷運的朋友, 一定知道在橘線時要搞清楚方向, 要不然得回頭才能到另外一邊相反的方向, 這個銀座線更慘, 進入錯誤的地下道入口閘門之後, 就在也回不到另外一個相反的方向, 得重新出閘門出站, 走出地下道, 再從另外一個地下道進入, 好不符合人性的設計。

fig 4. 銀座線往淺草方向

附近就是阿美橫丁, 有名的購物街, 在這裡吃了我上次沒能吃到的燒肉丼飯, 果然好吃阿!



用餐後已經很晚了, 大概是晚上八點, 附近的店家已經慢慢要打烊了, 好不容易看到一家大國藥妝店, 裡頭好多人, 都是說中文的, 也好不容易選好商品, 準備結帳, 卻發現某個物品缺貨, 真是掃興, 乘興而來, 敗興而歸, 沒關係, 今天才第一天, 還有時間可以大採購的。期待明天的輕井澤一行。

2018年5月11日 星期五

補繳汽車牌照稅

文章量見底了
汽車牌照稅每年 4 月繳, 期限是到 0430, 而 5 月要繳房屋稅、所得稅, 還真難應付。

不過這次 201804 的汽車牌照稅我忘記繳了, 等到我想起來的時候, 已經 5 月初了, 該怎麼辦呢? 可以去監理處補繳, 不過當我打電話去監理處問時, 他要我去問稅務局, 而稅務局幫我查到我的汽車並不是在這個縣市的車籍, 所以又打到車籍縣市的稅務局, 就是她告知我可以到監理處補繳, 不過有個更好的方法, 稅務局的人員幫我補單, 又重新寄了一張汽車牌照稅單給我, 並且設定繳稅期限是 20180515, 真是貼心的服務, 就這樣, 我的汽車牌照稅是 20180510 繳的, 而且不用被罰滯納金, 謝謝這些公務人員。

連這個都可以當 blog 寫, 表示文章水庫量真的見底了, 和台灣的水庫一樣, 低水位呢!

2018年5月4日 星期五

c 語言, 刪除執行過的 function

看到《C是否能指定函數在特定記憶體, 執行後抹除?》這問題我覺得有趣, 想試試看能不能辦到?

想法就是找出 function 的位址以及長度, 然後用 memset 填 0 即可, 原理很簡單, 實作就麻煩了不只一點。

ref:
How to get the length of a function in bytes?

首先要怎麼得到被刪除的 function address, size?
function address 很簡單, 就是 function 名稱, function 名稱本身就是位址, 沒問題, 問題在怎麼取得這個 function 的 size。

一開始我用了 list 1 L37 的方法, 把 f2 - f1 得到的 size 當作 f1() 的長度, 但是這有個前提, 編譯器產生的程式碼得把 f2 緊緊接在 f1 之後, 這是有保證的嗎? 我不確定, 不過要是擔心的話, 可以用 objdump 反組譯確認, 我當然是確認過了。

另外一個作法麻煩點, 相依於編譯器開發工具, 我修改了內建的 linker script, 插入 list 2 L24 ~ L31 的 linker script 指令, 計算出 f1 真正的長度, 這是最保險的方式, 可惜沒有可攜性。再使用 list 1 L29 ~L32 取得 f1() 長度。

有了長度, 位址, 把它傳給 memset 就結束了嗎? 還沒, 我們在 linux os 的控制下, 記憶體不是 user mode 程式要幹麻就能幹麻, 得把這個記憶體設定為可執行、可讀取、可寫入, 才可以用 memset, 這是 list 1 L47 在做的事情, 還沒完, 在這之前, 得先要算出 page align 的位址才可以, 因為 mprotect 需要傳入 page align 的位址。list 1 L38 ~ L42 就是在計算這個位址, 好了, 真的結束了, 在 list 1 L58 之後, 會發出 segment fault 的錯誤, 因為 f1 不再存在了。

list 1. erase_function.cpp
 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 // after call f1(), erase f1()
 4 
 5 #include <malloc.h>
 6 #include <cstring>
 7 
 8 #include <cstdint>
 9 
10 #include <unistd.h>
11 #include <sys/mman.h>
12 
13 using namespace std;
14 
15 // ref: https://stackoverflow.com/questions/4156585/how-to-get-the-length-of-a-function-in-bytes
16 __attribute__((noinline, section("f1_sec"))) 
17 void f1()
18 {
19   printf("xx f1\n");
20 }
21 
22 void f2()
23 {
24   printf("xx f2\n");
25 }
26 
27 int main(int argc, char *argv[])
28 {    
29   extern unsigned char f1_sec_start[];
30   extern unsigned char f1_sec_end[];
31 
32   printf("f1_sec_end - f1_sec_start: %p\n", f1_sec_end - f1_sec_start);
33 
34   f1();
35   f2();
36 
37   auto len = ((char *)f2-(char *)f1);
38   auto pagesize = getpagesize();
39   printf("pagesize: %d\n", pagesize);
40 
41   uintptr_t b = (((uintptr_t)f1)+4095 & (~4095));
42   b = (uintptr_t)f1 - (uintptr_t)f1 % pagesize;
43 
44   printf("f1: %p\n", f1);
45   printf("b: %p\n", b);
46 
47   if (0 == mprotect((void*)b, pagesize, PROT_WRITE|PROT_READ|PROT_EXEC))
48   {
49     printf("set to write|read|exec\n");
50   }
51   else
52   {
53     perror("mprotect fail\n");
54   }
55 
56   memset((void*)f1, 0, len);
57   f2();
58   f1();
59 
60   //printf("len: %p\n", len);
61 
62   return 0;
63 }



list 2. ld --verbose f1_sec.diff
 1 --- c1.ld 2018-03-19 09:58:21.161399780 +0800
 2 +++ c.ld 2018-03-19 10:06:07.377399780 +0800
 3 @@ -1,16 +1,3 @@
 4 -GNU ld (GNU Binutils for Debian) 2.29.1
 5 -  Supported emulations:
 6 -   elf_x86_64
 7 -   elf32_x86_64
 8 -   elf_i386
 9 -   elf_iamcu
10 -   i386linux
11 -   elf_l1om
12 -   elf_k1om
13 -   i386pep
14 -   i386pe
15 -using internal linker script:
16 -==================================================
17  /* Script for -z combreloc: combine and sort reloc sections */
18  /* Copyright (C) 2014-2017 Free Software Foundation, Inc.
19     Copying and distribution of this script, with or without modification,
20 @@ -66,6 +53,14 @@
21    .plt            : { *(.plt) *(.iplt) }
22  .plt.got        : { *(.plt.got) }
23  .plt.sec        : { *(.plt.sec) }
24 +
25 +  f1_sec :
26 +  {
27 +    f1_sec_start = .;
28 +    *(f1_sec)
29 +    f1_sec_end = .;
30 +  }
31 +
32    .text           :
33    {
34      *(.text.unlikely .text.*_unlikely .text.unlikely.*)
35 @@ -242,6 +237,3 @@
36    .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
37    /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
38  }
39 -
40 -
41 -==================================================

這樣的功能有實用性嗎?
skype 為了避免被反組譯出來, 就用了類似的技巧, 將自己初始化的函式消去。

2018年4月27日 星期五

Multi-dimensional Arrays in C - c 的多維陣列

寫俄羅斯方塊時, 搞反了 2 維陣列的維度, 逼自己好好反省一下。

m_array.c
 1 #include <stdio.h>
 2 
 3 int main(int argc, char *argv[])
 4 {
 4.5   // int daytab[3][13] 每 row 有 13 個元素
 5   unsigned char a[5][4][6][8];
 6 
 7   printf("a: %p\n", a);
 8   printf("&a[3][3][2][7]: %p\n", &a[3][3][2][7]);
 9   printf("offset: %d\n", (&a[3][3][2][7]) - (&a[0][0][0][0]));
10   return 0;
11 }

a: 0x7fff98a74220
&a[3][3][2][7]: 0x7fff98a74507
offset: 743


m_array.c L4.5 宣告了 2 維陣列, 誰是 3, 誰是 13 呢? 老是搞不清楚, 以 row, column 來說, row 是 13, column 是 3。

4 維空間, 厄 ... 是 4 維陣列無法用 row, column 來說明, 所以遇到 unsigned char a[5][4][6][8] 該怎麼想呢? 長的像以下的圖, 下圖只到 [4][6][8], 有 5 個以下的圖, 就是 [5][4][6][8] 了。

a[3][2][5][7] 的位址該怎麼計算呢?

a
[3] - a3
[2] - b2
[5] - c5
[7] - d7

在 d7 的那個紅色位置。

1


1 2 3 4 5 6 7 8

2







3







4







5







6







2

1







2







3







4







5 , 1 2 3 4 5 6 7 8

6







3























































4
























































2 [4][6][8]

a3
1


1 2 3 4 5 6 7 8

2







3







4







5







6







b2

1







2







3







4







c5 , 1 2 3 4 5 6 d7 8

6







3























































4
























































4 [4][6][8]

5 [4][6][8]

2018年4月20日 星期五

20171217 台南偶遇 - BJD 二手小市集 2



台南偶遇 - BJD 二手小市集》是場 bjd 的二手物品交流活動, 南部少數的娃場活動。

  • 活動地點:台南文化創意產業園區4樓L4B   
  • 活動地址:台南市東區北門路二段16號4樓 
  • 入場門票:全票80 NTD/張
為南部娃友提供了相互交流的活動, 也可以把用不到的娃物出清給有需要的娃友, 我很喜歡類似的活動, 因為這是一個可以搶便宜的時候, 二手娃物通常娃友都保存的很好, 而定價也很便宜, 是補充物資的好時機。



地點也是在很便利的地方, 從台南火車站前站大門出來後, 右轉經過 7-11, 走路大約5分鐘, 就可以看到不怎麼有文化創意的台南文化創意產業園區, 這個地點很好, 但在推廣文化創意產業上, 好像力道有些不足, 錢不知道都補助到哪些地方去了。這種不會污染土地的產業, 政府更應該大力的鼓勵才是, 像那種會破壞土地的製造業, 還是少點, 能像日本的動漫產業發達, 那不是很好嗎?



和台北的娃場比起來, 場地小了點, 攤位數也少了點, 但不阻礙 bjd 玩家, 大家還是逛的很開心, 彼此交流自己的養娃心得, 我也趁此又多進補了相關知識。

fig 1. 一步蓮華
除了賣東西, 攤位主通常會火力展示一下自己的娃娃, 這時候就可以欣賞一下每個人不同的品味, 品味沒有高下之分, 只有個人的喜好不同, 各有各的特色, 遇到喜歡的, 還可以回家偷偷模仿, 打造出自己喜愛的風格。

fig 1 的一步蓮華服飾, 個人覺得很漂亮, 這是一位娃媽自己訂製的衣服, 她還有一件藥師慕少艾, 這是霹靂布袋戲的角色, 難怪我第一點看到時就覺得很眼熟, 這個是 4 分娃, 娃媽說穿在 3 分娃會比較適合, 我順道問了有襲滅天來的嗎? 她說沒有, 真是可惜了, 可以湊成一對呢!

由於攤位真的不多, 沒多久我就逛完一圈了, 之後便再逛一圈, 看看有沒有漏網之魚。

最後購買了 fig 2, fig 3 的配件, 比起動輒上千的服飾, 這次的花費還算節省, 通常我最喜歡在這樣的二手市集找頭髮, 所以頭髮一般我都不太買新的。

fig 2 的雨傘算是一個可愛的配件, 之前有看過日本和室的紙傘, 不過我還是喜歡現代風格的雨傘, 和室紙傘要和和服搭配看起來才有一致的風格, 目前我還沒有收錄和服, 而且我喜歡雨傘這樣的機械裝置, 雖然只是簡單的打開和關閉, 但就是吸引我, 購入之後, 收收開開玩了好幾次, 真的是很有趣的配件。

搭配剛購入的持物手, 剛剛好可以握住這把雨傘, 再搭配剛購入的服飾、頭髮, 豐富了娃娃的造型, 這些配件、衣服、手型來的剛剛好。荷包君受到不少重擊, 娃坑 ... 錢坑也。

fig 3 是 saber 假髮, 看到便宜就購入了, 目前我好像收太多 saber 的頭髮, 有馬尾版本, 另外就是這個版本。

fig 2. 雨傘: 80; 髮夾: 20; 頭髮: 250fig 3. saber 頭髮 250


2018年4月12日 星期四

c++ virtual function 的實作 by cfront

c++ virtual function 被很多人拿來研究, 由於沒有 cfront, 大部分的人都是從反組譯來觀察, 太苦了。

目前我已經把 cfront 建構出來, 可以使用 cfront 來看看 virtual function 轉出的 c code 長什麼樣, 破解 c++ virtual function。

hello_a.C
 1 #include <stream.h>
 2 
 3 class A
 4 {
 5   public:
 6     virtual void foo(int a = 0)
 7     {
 8       printf("A %d\n", a);
 9     }
10     virtual void va(int a)
11     {
12       printf("va: A %d\n", a);
13     }
14 };
15 
16 class B : public A
17 {
18   public:
19     virtual void foo(int a = 1)
20     {
21       printf("B a: %d\n", a);
22     }
23 };
24 
25 
26 main()
27 {
28   A *p = new A();
29   p->foo();
30   p->va(25);
31 }

hello.a.c 是 cfont 轉出來的 c code, 31 行的 c++ 程式碼透過 cfront 轉出 773 行 c code, 先來看看 class A, class B 被轉成什麼? hello.a.c L633, L643 就是對應的 class A, class B, 被轉成 strcut:
633 struct A { /* sizeof A == 8 */
636   struct __mptr *__vptr__1A ;
637 };
639 
643 struct B { /* sizeof B == 8 */
646   struct __mptr *__vptr__1A ;
647 };
裡頭有一個 __vptr__1A:
646 struct __mptr *__vptr__1A ;
struct __mptr 定義在 L17。
17 struct __mptr {short d; short i; __vptp f; };
注意其中的 __vptp f 即可, 這個就是用來儲存 virtual function, 其實 virtual function 就是一般的 c function, 所以也只是把 virtual function 的位址存起來。

再來是 L766 的 __ptbl_vec__hello_C_, 這邊建構了__vtbl__1A__hello_C
766 struct __mptr* __ptbl_vec__hello_C_[] = {
767 __vtbl__1A__hello_C,
768 
769 };
__vtbl__1A__hello_C 在 L699 定義:
699 struct __mptr __vtbl__1A__hello_C[] = {0,0,0,
700 0,0,(__vptp)foo__1AFi ,
701 0,0,(__vptp)va__1AFi ,
702 0,0,0};
__vtbl__1A__hello_C[0]: 0,0,0
__vtbl__1A__hello_C[1]: 0,0, foo__1AFi 就是 class A 的 virtual void foo(int a = 0)
__vtbl__1A__hello_C[2]: 0,0, va__1AFi 就是 class A virtual void va(int a)
A *p = new A(); 會用 new (__nw__FUl 就是 new) 建構 struct A, 把 p->__vptr__1A = __ptbl_vec__hello_C_[0]
對應到 hello.a.c L668
668 __1p = ( (__0__X52 = 0 ), ( ((__0__X52 || (__0__X52 = (struct A *)__nw__FUl ( (unsigned long )(sizeof (struct A))) ))?(__0__X52 ->
669 #line 28 "hello.C"
670 __vptr__1A = (struct __mptr *) __ptbl_vec__hello_C_[0]):0 ), __0__X52 ) ) ;
p->foo(); 就是執行 p->__vptr__1A[1].f

對應到 hello.a.c L671
671 ((*(((void (*)(struct A *__0this , int __2a ))(__1p -> __vptr__1A [1]).f))))( ((struct A *)((((char *)__1p ))+ (__1p -> __vptr__1A [1]).d)), 0 ) ;
p->va(25); 就是執行 p->__vptr__1A[2].f
對應到 hello.a.c L672
672 ((*(((void (*)(struct A *__0this , int __2a ))(__1p -> __vptr__1A [2]).f))))( ((struct A *)((((char *)__1p ))+ (__1p -> __vptr__1A [2]).d)), 25 ) ;
這些很恐怖的轉型/設定程式碼就是在做這些事情 (花點時間應該可以看懂), 也就是為什麼 class B 可以呼叫 class A 的 virtaul function va 的祕密。

hello.a.c
  1 #line 1 "hello.C"
  2 
  3 /* <<AT&T C++ Language System <3.0.3> 05/05/94>> */
  4 char __cfront_version_303_xxxxxxxx;
  5 /* < hello.C > */
  6 
  7 #pragma lib "ape/libap.a"
  8 
  9 #pragma lib "c++/libC.a"
 10 
 11 #line 1 "hello.C"
 12 void *__vec_new (void *, int , int , void *);
 13 
 14 #line 1 "hello.C"
 15 void __vec_delete (void *, int , int , void *, int , int );
 16 typedef int (*__vptp)(void);
 17 struct __mptr {short d; short i; __vptp f; };
 18 
 19 #line 1 "hello.C"
 20 extern struct __mptr* __ptbl_vec__hello_C_[];
 21 
632 #line 4 "hello.C"
633 struct A { /* sizeof A == 8 */
634 
635 #line 14 "hello.C"
636 struct __mptr *__vptr__1A ;
637 };
638 struct B;
639 
640 #line 14 "hello.C"
641 
642 #line 17 "hello.C"
643 struct B { /* sizeof B == 8 */
644 
645 #line 14 "hello.C"
646 struct __mptr *__vptr__1A ;
647 };
648 
649 #line 14 "hello.C"
650 
651 #line 6 "hello.C"
652 static void foo__1AFi (struct A *__0this , int __2a );
653 
654 #line 10 "hello.C"
655 static void va__1AFi (struct A *__0this , int __2a );
656 
657 #line 26 "hello.C"
658 int main (void ){ _main(); 
659 #line 27 "hello.C"
660 { 
661 #line 28 "hello.C"
662 struct A *__1p ;
663 
664 #line 29 "hello.C"
665 struct A *__0__X52 ;
666 
667 #line 28 "hello.C"
668 __1p = ( (__0__X52 = 0 ), ( ((__0__X52 || (__0__X52 = (struct A *)__nw__FUl ( (unsigned long )(sizeof (struct A))) ))?(__0__X52 ->
669 #line 28 "hello.C"
670 __vptr__1A = (struct __mptr *) __ptbl_vec__hello_C_[0]):0 ), __0__X52 ) ) ;
671 ((*(((void (*)(struct A *__0this , int __2a ))(__1p -> __vptr__1A [1]).f))))( ((struct A *)((((char *)__1p ))+ (__1p -> __vptr__1A [1]).d)), 0 ) ;
672 ((*(((void (*)(struct A *__0this , int __2a ))(__1p -> __vptr__1A [2]).f))))( ((struct A *)((((char *)__1p ))+ (__1p -> __vptr__1A [2]).d)), 25 ) ;
673 }
674 } 
675 #line 31 "hello.C"
676 void __sti__hello_C_main_ (void )
677 #line 664 "incl-master/incl-linux32/iostream.h"
678 { __ct__13Iostream_initFv ( & iostream_init ) ;
679 
680 #line 664 "incl-master/incl-linux32/iostream.h"
681 }
682 
683 #line 31 "hello.C"
684 void __std__hello_C_main_ (void )
685 #line 664 "incl-master/incl-linux32/iostream.h"
686 { __dt__13Iostream_initFv ( & iostream_init , 2) ;
687 
688 #line 664 "incl-master/incl-linux32/iostream.h"
689 }
690 static void foo__1BFi (
691 #line 19 "hello.C"
692 struct B *__0this , 
693 #line 19 "hello.C"
694 int __2a );
695 struct __mptr __vtbl__1B__hello_C[] = {0,0,0,
696 0,0,(__vptp)foo__1BFi ,
697 0,0,(__vptp)va__1AFi ,
698 0,0,0};
699 struct __mptr __vtbl__1A__hello_C[] = {0,0,0,
700 0,0,(__vptp)foo__1AFi ,
701 0,0,(__vptp)va__1AFi ,
702 0,0,0};
703 static void foo__1BFi (struct B *__0this , 
704 #line 19 "hello.C"
705 int __2a )
706 #line 20 "hello.C"
707 { 
708 #line 21 "hello.C"
709 printf ( (const char *)"B a: %d\n",
710 #line 21 "hello.C"
711 __2a ) ;
712 }
713 
714 #line 10 "hello.C"
715 static void va__1AFi (struct A *__0this , 
716 #line 10 "hello.C"
717 int __2a )
718 #line 11 "hello.C"
719 { 
720 #line 12 "hello.C"
721 printf ( (const char *)"va: A %d\n",
722 #line 12 "hello.C"
723 __2a ) ;
724 }
725 
726 #line 6 "hello.C"
727 static void foo__1AFi (struct A *__0this , 
728 #line 6 "hello.C"
729 int __2a )
730 #line 7 "hello.C"
731 { 
732 #line 8 "hello.C"
733 printf ( (const char *)"A %d\n",
734 #line 8 "hello.C"
735 __2a ) ;
736 }
766 struct __mptr* __ptbl_vec__hello_C_[] = {
767 __vtbl__1A__hello_C,
768 
769 };
770 
771 #line 31 "hello.C"
772 
773 /* the end */

hello_b.C 和 hello_a.C 不同之處在於 new B(), 對於整個轉出來的程式當中, 只有一點點的不同:

hello_b.C
 1 #include <stream.h>
 2 
 3 class A
 4 {
 5   public:
 6     virtual void foo(int a = 0)
 7     {
 8       printf("A %d\n", a);
 9     }
10     virtual void va(int a)
11     {
12       printf("va: A %d\n", a);
13     }
14 };
15 
16 class B : public A
17 {
18   public:
19     virtual void foo(int a = 1)
20     {
21       printf("B a: %d\n", a);
22     }
23 };
24 
25 
26 main()
27 {
28   A *p = new B();
29   p->foo();
30   p->va(25);
31 }

hello.b.c 733

773 struct __mptr* __ptbl_vec__hello_C_[] = {
774 __vtbl__1A__hello_C,
775 __vtbl__1B__hello_C,
776 
777 };

多建構了一個 __vtbl__1B__hello_C
695 struct __mptr __vtbl__1B__hello_C[] = {0,0,0,
696 0,0,(__vptp)foo__1BFi ,
697 0,0,(__vptp)va__1AFi ,
698 0,0,0};

__vtbl__1B__hello_C[0]: 0,0,0
__vtbl__1B__hello_C[1]: 0,0, foo__1AFi 就是 class B 的 virtual void foo(int a = 1)
__vtbl__1B__hello_C[2]: 0,0, va__1AFi 就是 class A 的 virtual void va(int a)

A *p = new B(); 會用 new 建構 struct B, 把 p->__vptr__1A = __ptbl_vec__hello_C_[1]
對應到 hello.b.c L671

671 __1p = (struct A *)( (__0__X52 = 0 ), ( ((__0__X52 || (__0__X52 = (struct B *)__nw__FUl ( (unsigned long )(sizeof (struct B)))
672 #line 28 "hello.C"
673 ))?( (__0__X52 = (struct B *)( (__0__X51 = (((struct A *)__0__X52 ))), ( ((__0__X51 || (__0__X51 = (struct A *)__nw__FUl ( (unsigned long
674 #line 28 "hello.C"
675 )(sizeof (struct A))) ))?(__0__X51 -> __vptr__1A = (struct __mptr *) __ptbl_vec__hello_C_[0]):0 ), __0__X51 ) ) ), (__0__X52 -> __vptr__1A = (struct __mptr *) __ptbl_vec__hello_C_[1])) :0 ),
676 #line 28 "hello.C"
677 __0__X52 ) ) ;
p->foo(); 對應到 hello.b.c L678
678 ((*(((void (*)(struct A *__0this , int __2a ))(__1p -> __vptr__1A [1]).f))))( ((struct A *)((((char *)__1p ))+ (__1p -> __vptr__1A [1]).d)), 0 ) ;
p->va(25); 對應到 hello.b.c L679
679 ((*(((void (*)(struct A *__0this , int __2a ))(__1p -> __vptr__1A [2]).f))))( ((struct A *)((((char *)__1p ))+ (__1p -> __vptr__1A [2]).d)), 25 ) ;
這些很恐怖的轉型/設定程式碼就是在做這些事情, 而呼叫 virtual function 的程式碼是相同的, 只有在設定 __vptr__1A 有所不同而已。 看懂這些資料結構之後, virtaul function 就沒有那麼神秘了。 至於
17 struct __mptr {short d; short i; __vptp f; };
神秘的 d, i, 應該是用在繼承上的, 可能是其他的繼承方式, 有興趣的朋友可以繼續追蹤下去。
hello.b.c
632 #line 4 "hello.C"
633 struct A { /* sizeof A == 8 */
634 
635 #line 14 "hello.C"
636 struct __mptr *__vptr__1A ;
637 };
638 struct B;
639 
640 #line 14 "hello.C"
641 
642 #line 17 "hello.C"
643 struct B { /* sizeof B == 8 */
644 
645 #line 14 "hello.C"
646 struct __mptr *__vptr__1A ;
647 };
648 
649 #line 23 "hello.C"
650 
651 #line 6 "hello.C"
652 static void foo__1AFi (struct A *__0this , int __2a );
653 
654 #line 10 "hello.C"
655 static void va__1AFi (struct A *__0this , int __2a );
656 
657 #line 26 "hello.C"
658 int main (void ){ _main(); 
659 #line 27 "hello.C"
660 { 
661 #line 28 "hello.C"
662 struct A *__1p ;
663 
664 #line 29 "hello.C"
665 struct B *__0__X52 ;
666 
667 #line 29 "hello.C"
668 struct A *__0__X51 ;
669 
670 #line 28 "hello.C"
671 __1p = (struct A *)( (__0__X52 = 0 ), ( ((__0__X52 || (__0__X52 = (struct B *)__nw__FUl ( (unsigned long )(sizeof (struct B)))
672 #line 28 "hello.C"
673 ))?( (__0__X52 = (struct B *)( (__0__X51 = (((struct A *)__0__X52 ))), ( ((__0__X51 || (__0__X51 = (struct A *)__nw__FUl ( (unsigned long
674 #line 28 "hello.C"
675 )(sizeof (struct A))) ))?(__0__X51 -> __vptr__1A = (struct __mptr *) __ptbl_vec__hello_C_[0]):0 ), __0__X51 ) ) ), (__0__X52 -> __vptr__1A = (struct __mptr *) __ptbl_vec__hello_C_[1])) :0 ),
676 #line 28 "hello.C"
677 __0__X52 ) ) ;
678 ((*(((void (*)(struct A *__0this , int __2a ))(__1p -> __vptr__1A [1]).f))))( ((struct A *)((((char *)__1p ))+ (__1p -> __vptr__1A [1]).d)), 0 ) ;
679 ((*(((void (*)(struct A *__0this , int __2a ))(__1p -> __vptr__1A [2]).f))))( ((struct A *)((((char *)__1p ))+ (__1p -> __vptr__1A [2]).d)), 25 ) ;
680 }
681 } 
682 #line 31 "hello.C"
683 void __sti__hello_C_main_ (void )
684 #line 664 "incl-master/incl-linux32/iostream.h"
685 { __ct__13Iostream_initFv ( & iostream_init ) ;
686 
687 #line 664 "incl-master/incl-linux32/iostream.h"
688 }
689 
690 #line 31 "hello.C"
691 void __std__hello_C_main_ (void )
692 #line 664 "incl-master/incl-linux32/iostream.h"
693 { __dt__13Iostream_initFv ( & iostream_init , 2) ;
694 
695 #line 664 "incl-master/incl-linux32/iostream.h"
696 }
697 static void foo__1BFi (
698 #line 19 "hello.C"
699 struct B *__0this , 
700 #line 19 "hello.C"
701 int __2a );
702 struct __mptr __vtbl__1B__hello_C[] = {0,0,0,
703 0,0,(__vptp)foo__1BFi ,
704 0,0,(__vptp)va__1AFi ,
705 0,0,0};
706 struct __mptr __vtbl__1A__hello_C[] = {0,0,0,
707 0,0,(__vptp)foo__1AFi ,
708 0,0,(__vptp)va__1AFi ,
709 0,0,0};
710 static void foo__1BFi (struct B *__0this , 
711 #line 19 "hello.C"
712 int __2a )
713 #line 20 "hello.C"
714 { 
715 #line 21 "hello.C"
716 printf ( (const char *)"B a: %d\n",
717 #line 21 "hello.C"
718 __2a ) ;
719 }
720 
721 #line 10 "hello.C"
722 static void va__1AFi (struct A *__0this , 
723 #line 10 "hello.C"
724 int __2a )
725 #line 11 "hello.C"
726 { 
727 #line 12 "hello.C"
728 printf ( (const char *)"va: A %d\n",
729 #line 12 "hello.C"
730 __2a ) ;
731 }
732 
733 #line 6 "hello.C"
734 static void foo__1AFi (struct A *__0this , 
735 #line 6 "hello.C"
736 int __2a )
737 #line 7 "hello.C"
738 { 
739 #line 8 "hello.C"
740 printf ( (const char *)"A %d\n",
741 #line 8 "hello.C"
742 __2a ) ;
743 }
744 
773 struct __mptr* __ptbl_vec__hello_C_[] = {
774 __vtbl__1A__hello_C,
775 __vtbl__1B__hello_C,
776 
777 };
778 
779 #line 31 "hello.C"
780 
781 /* the end */

2018年3月29日 星期四

[懷舊] 向 cfront 致敬, 使用 cfront 來編譯 c++ 程式

華麗的 c++ 與華麗的娃衣
cfront 是幹麻的? c++ 程式員應該不陌生, 他是把 c++ 程式轉成 c, 再用 c 編譯器編譯出最後執行檔的轉譯程式。知道的 c++ 開發者應該很多, 但看過、甚至執行過 cfront 的人應該就很少了。

我一直都在找 cfront 的 source code, 希望可以編譯/執行起來看看, 這樣可以很清楚的知道, virtual function, 繼承的 class, template 到底是怎麼轉成 c code 的, cfront 不支援 exception, 因為這功能複雜到超過 cfront 的能力了。

Cfront
Cfront 4.0 was abandoned in 1993 after a failed attempt to add exception support.[1] The C++ language had grown beyond its capabilities

Comeau C/C++ 也可以做到類似的事情, 不過要錢, 沒免費版可以試用。

這個 https://github.com/seyko2/cfront-3 就是 cfront source code 了, 我想在 linux 下編譯, 之前嘗試過一次, 失敗了, 這次有新版再來挑戰一次, 向 bjarne stroustrup 博士致敬, 感謝他發明出 c++ 這麼複雜的語言, 整死開發 c++ 編譯器的開發人員, 當然還有學習 c++ 的程式員。

我修改過的版本在 https://github.com/descent/cfront-3, 切到 can_build_in_linux branch 即可, 你得先會用 git 才行, 好吧! git checkout can_build_in_linux 就可以了。

Makefile
 1 #Makefile for the CC translator
 2 # BSD 4.2 or later should first run bsd.sed in the scratch directory
 3 # and set CCFLAGS=-DBSD
 4 # also set BSD=1
 5 
 6 CCFLAGS=-Os
 7 scratchCC ?= gcc
 8 
 9 BSD=
10 PATH:=$(CURDIR):$(PATH)
11 
12 #For first make (bootstrap):
13 # make scratch  #on system V, BSD 4.1 or earlier
14 #Otherwise:
15 # make
16 #
17 
18 CC = CC
19 
20 all: libC.a munch cfront
21  :
22 
23 libC.a: always
24  cd lib/mk; $(MAKE) CC=$(CC) CCFLAGS="$(CCFLAGS)" BSD=$(BSD)
25  mv lib/mk/libC.a .
26 
27 munch: _munch/munch.c
28  cc -o munch _munch/munch.c
29 
30 cfront: always
31  cd src; $(MAKE) CXX=$(CC) CCFLAGS="$(CCFLAGS)"
32  mv src/cfront cfront
33  
34 scratch: always
35  cd scratch; $(MAKE) CC=$(scratchCC) BSD=$(BSD) CCFLAGS="$(CCFLAGS)"
36 
37 #This target will populate the scratch directories with good-old-c
38 #files.  This is used to port to another machine.
39 
40 fillscratch:
41  make -C src szal.result y.tab.C yystype.h
42  cp src/_stdio.c scratch/src/
43  cd scratch/src; $(CC) -I../../src         -I../../incl -Fc -..c ../../src/*.C;
44  cd scratch/lib; $(CC) -I../../lib/complex -I../../incl -Fc -..c ../../lib/new/*.C
45  cd scratch/lib; $(CC) -I../../lib/complex -I../../incl -Fc -..c ../../lib/static/*.C
46  cp _munch/*.c scratch/mnch/
47 
48 always: 

Makefile L20
all: libC.a munch cfront

總共有 3 個部份要編譯, libC.a, munch, cfront 我分 3 次手動編譯:

libC.a
cd lib/mk
make CC=gcc CCFLAGS="-Os -I../../incl-master/incl-linux32/"

也可以用 cfront 編譯, 不過先要編出 cfront 才行, CC3 就會使用 cfront 來編譯。後面會提到怎麼使用 cfront 編譯出一個可以執行的檔案, 這邊的 libC.a 就需要用 cfront 來編譯, 否則會有奇怪的 link 錯誤。

編出 cfront 之後 (需要複製到 cfront-3 目錄下), 在 cfront-3 目錄下打 make libC.a 即可。

munch 使用 cfront 編譯時, 需要用到的一個工具程式。
gcc -o munch _munch/munch.c
這麼簡單, 不需要說明, 這是 .c 不用出動 cfront。

cfront
編譯 cfront 會用到 yacc, can_build_in_linux branch 除了修改程式碼與編譯參數, 還有 yacc 需要改為使用 byacc (Berkeley YACC, 修改 Makefile), 使用 apt-get 來安裝 byacc。

apt-get install byacc

bison 會有以下錯誤訊息:

bison.err
1 gram.y:2340.31-32: error: $$ for the midrule at $3 of ‘statement’ has no declared type
2         |  ID COLON { $$ = $1; stmt_seen=1; } caselab_stmt
3                                ^^
4 gram.y:2344.34-35: error: $$ for the midrule at $3 of ‘statement’ has no declared type
5         |  TNAME COLON { $$ = new name($<pn>1->string); stmt_seen=1; } caselab_stmt
6                                   ^^

編譯指令:
cd src
make CC=gcc CCFLAGS="-Os -fpermissive -I../incl-master/incl-linux32/"

看到以下錯誤免著驚, 這是藥氣等待行, cfront 其實已經編譯出來了。

g++ -o cfront Bits.o alloc.o block.o dcl.o dcl2.o dcl3.o dcl4.o del.o discrim.o error.o expand.o expr.o expr2.o expr3.o find.o hash.o lalex.o lex.o main.o norm.o norm2.o print.o print2.o repr.o simpl.o simpl2.o size.o table.o template.o tree_copy.o tree_walk.o typ.o typ2.o y.tab.o _stdio.o
Makefile:23: recipe for target 'cfront' failed
make: [cfront] Error 1 (ignored)
cp cfront ..

cfront 編好了。

cd pt
make CC=gcc

pt 目錄有一些工具程式是編譯用到 string class 的時候會用到的。
ref: cfront-3/demo/string/
string class 我沒成功編譯出來。

也可以用 cfront 編譯 cfront 自己, 不過先要編出 cfront 才行, CC3 就會使用 cfront 來編譯, 不過有些問題, 得手動修改, 我懶的改, 沒成功用 cfront 編譯 cfront 自己。

終於 build 出來了, 執行一下, 感動阿!

run cfront
1 descent@debian64:cfront-3$ ./cfront
2 # 1 ""
3
4 /* <<AT&T C++ Language System <3.0.3> 05/05/94>> */
5 char __cfront_version_303_xxxxxxxx;

用 cfont 編譯 demo/hello/hello.C

demo/hello/hello.C
1 #include <stream.h>
2 
3 main()
4 {
5     cout << "Hello, World!\n";
6 }

有點難度, 步驟如下:
cp hello.C incl-master/incl-linux32
gcc -I. -E hello.C > hh.c
../../cfront < hh.c > h3.c

有沒很感動, 輸出一個 c 的 c++ 程式, bjarne 有你的。

h3.c
  1 # 1 ""
  2 
  3 /* <<AT&T C++ Language System <3.0.3> 05/05/94>> */
  4 char __cfront_version_303_xxxxxxxx;
  5 
  6 #pragma lib "ape/libap.a"
  7 
  8 #pragma lib "c++/libC.a"
  9 
 10 # 1 ""
 11 char *__vec_new ();
 12 
 13 # 1 ""
 14 char __vec_delete ();
 15 typedef int (*__vptp)();
 16 struct __mptr {short d; short i; __vptp f; };
 17 
 18 # 1 ""
 19 extern struct __mptr* __ptbl_vec___[];
 20 
 21 # 1 ""
 22 
 23 # 49 "./iostream.h"
 24 typedef long streampos ;
 25 typedef long streamoff ;
 26 enum __Q2_3ios8io_state { goodbit__Q2_3ios8io_state = 0, eofbit__Q2_3ios8io_state = 1, failbit__Q2_3ios8io_state = 2, badbit__Q2_3ios8io_state = 4, hardfail__Q2_3ios8io_state = 128} ;
 27 enum __Q2_3ios9open_mode { in__Q2_3ios9open_mode = 1, out__Q2_3ios9open_mode = 2, ate__Q2_3ios9open_mode = 4, app__Q2_3ios9open_mode = 8, trunc__Q2_3ios9open_mode = 16, nocreate__Q2_3ios9open_mode = 32, noreplace__Q2_3ios9open_mode = 64} ;
 28 enum __Q2_3ios8seek_dir { beg__Q2_3ios8seek_dir = 0, cur__Q2_3ios8seek_dir = 1, end__Q2_3ios8seek_dir = 2} ;
 29 enum __Q2_3ios4__E1 { skipws__Q2_3ios4__E1 = 1, left__Q2_3ios4__E1 = 2, right__Q2_3ios4__E1 = 4, internal__Q2_3ios4__E1 = 8, dec__Q2_3ios4__E1 = 16, oct__Q2_3ios4__E1 = 32, hex__Q2_3ios4__E1 = 64, showbase__Q2_3ios4__E1 = 128, showpoint__Q2_3ios4__E1 = 256, uppercase__Q2_3ios4__E1 = 512, showpos__Q2_3ios4__E1 = 1024, scientific__Q2_3ios4__E1 = 2048, fixed__Q2_3ios4__E1 = 4096, unitbuf__Q2_3ios4__E1 = 8192,
 30 # 54 "./iostream.h"
 31 stdio__Q2_3ios4__E1 = 16384} ;
 32 enum __Q2_3ios4__E2 { skipping__Q2_3ios4__E2 = 512, tied__Q2_3ios4__E2 = 1024} ;
 33 struct ios { /* sizeof ios == 88 */
 34 
 35 # 153 "./iostream.h"
 36 int nuser__3ios ;
 37 
 38 # 155 "./iostream.h"
 39 union ios_user_union *x_user__3ios ;
 40 
 41 # 162 "./iostream.h"
 42 struct streambuf *bp__3ios ;
 43 
 44 # 168 "./iostream.h"
 45 int state__3ios ;
 46 int ispecial__3ios ;
 47 int ospecial__3ios ;
 48 int isfx_special__3ios ;
 49 int osfx_special__3ios ;
 50 int delbuf__3ios ;
 51 struct ostream *x_tie__3ios ;
 52 long x_flags__3ios ;
 53 short x_precision__3ios ;
 54 char x_fill__3ios ;
 55 short x_width__3ios ;
 56 
 57 # 186 "./iostream.h"
 58 int assign_private__3ios ;
 59 
 60 # 193 "./iostream.h"
 61 struct __mptr *__vptr__3ios ;
 62 };
 63 
 64 # 84 "./iostream.h"
 65 extern long basefield__3ios ;
 66 
 67 # 86 "./iostream.h"
 68 extern long adjustfield__3ios ;
 69 
 70 # 88 "./iostream.h"
 71 extern long floatfield__3ios ;
 72 
 73 # 150 "./iostream.h"
 74 extern long nextbit__3ios ;
 75 extern long nextword__3ios ;
 76 
 77 # 180 "./iostream.h"
 78 extern char (*stdioflush__3ios )();
 79 
 80 # 195 "./iostream.h"
 81 struct streambuf { /* sizeof streambuf == 80 */
 82 short alloc__9streambuf ;
 83 short x_unbuf__9streambuf ;
 84 char *x_base__9streambuf ;
 85 char *x_pbase__9streambuf ;
 86 char *x_pptr__9streambuf ;
 87 char *x_epptr__9streambuf ;
 88 char *x_gptr__9streambuf ;
 89 char *x_egptr__9streambuf ;
 90 char *x_eback__9streambuf ;
 91 int x_blen__9streambuf ;
 92 
 93 # 370 "./iostream.h"
 94 struct __mptr *__vptr__9streambuf ;
 95 };
 96 
 97 # 1 ""
 98 extern char __dl__FPv ();
 99 
100 # 246 "./iostream.h"
101 
102 # 255 "./iostream.h"
103 int doallocate__9streambufFv ();
104 
105 # 258 "./iostream.h"
106 int underflow__9streambufFv ();
107 
108 # 369 "./iostream.h"
109 int x_snextc__9streambufFv ();
110 
111 # 259 "./iostream.h"
112 int pbackfail__9streambufFi ();
113 
114 # 257 "./iostream.h"
115 int overflow__9streambufFi ();
116 
117 # 24 "./string.h"
118 extern char *memcpy ();
119 
120 # 229 "./iostream.h"
121 
122 # 265 "./iostream.h"
123 int xsputn__9streambufFPCci ();
124 
125 # 234 "./iostream.h"
126 
127 # 266 "./iostream.h"
128 int xsgetn__9streambufFPci ();
129 
130 # 372 "./iostream.h"
131 struct istream { /* sizeof istream == 112 */
132 
133 # 493 "./iostream.h"
134 int x_gcount__7istream ;
135 
136 # 503 "./iostream.h"
137 struct __mptr *__vptr__7istream ;
138 struct ios *Pios;
139 struct ios Oios;
140 };
141 
142 # 489 "./iostream.h"
143 int do_ipfx__7istreamFi ();
144 
145 # 298 "./iostream.h"
146 
147 # 302 "./iostream.h"
148 
149 # 418 "./iostream.h"
150 struct istream *rs_complicated__7istreamFRUc ();
151 
152 # 298 "./iostream.h"
153 
154 # 302 "./iostream.h"
155 
156 # 419 "./iostream.h"
157 struct istream *rs_complicated__7istreamFRc ();
158 
159 # 429 "./iostream.h"
160 struct istream *get__7istreamFPcic ();
161 
162 # 298 "./iostream.h"
163 
164 # 292 "./iostream.h"
165 
166 # 436 "./iostream.h"
167 struct istream *get_complicated__7istreamFRUc ();
168 
169 # 298 "./iostream.h"
170 
171 # 292 "./iostream.h"
172 
173 # 437 "./iostream.h"
174 struct istream *get_complicated__7istreamFRc ();
175 
176 # 377 "./iostream.h"
177 
178 # 292 "./iostream.h"
179 
180 # 163 "./iostream.h"
181 
182 # 377 "./iostream.h"
183 
184 # 281 "./iostream.h"
185 
186 # 480 "./iostream.h"
187 struct istream *read__7istreamFPci ();
188 
189 # 260 "./iostream.h"
190 int sync__9streambufFv ();
191 
192 # 505 "./iostream.h"
193 struct ostream { /* sizeof ostream == 104 */
194 
195 # 610 "./iostream.h"
196 struct __mptr *__vptr__7ostream ;
197 struct ios *Pios;
198 struct ios Oios;
199 };
200 
201 # 601 "./iostream.h"
202 int do_opfx__7ostreamFv ();
203 char do_osfx__7ostreamFv ();
204 
205 # 538 "./iostream.h"
206 struct ostream *complicated_put__7ostreamFc ();
207 
208 # 324 "./iostream.h"
209 
210 # 163 "./iostream.h"
211 
212 # 568 "./iostream.h"
213 struct ostream *ls_complicated__7ostreamFc ();
214 
215 # 324 "./iostream.h"
216 
217 # 163 "./iostream.h"
218 
219 # 569 "./iostream.h"
220 struct ostream *ls_complicated__7ostreamFUc ();
221 
222 # 324 "./iostream.h"
223 
224 # 163 "./iostream.h"
225 
226 # 572 "./iostream.h"
227 struct ostream *__ls__7ostreamFi ();
228 
229 # 329 "./iostream.h"
230 
231 # 163 "./iostream.h"
232 
233 # 589 "./iostream.h"
234 
235 # 612 "./iostream.h"
236 struct iostream { /* sizeof iostream == 128 */
237 
238 # 493 "./iostream.h"
239 int x_gcount__7istream ;
240 
241 # 503 "./iostream.h"
242 struct __mptr *__vptr__7istream ;
243 struct ios *Pios;
244 struct ostream Oostream;
245 };
246 
247 # 620 "./iostream.h"
248 struct istream_withassign { /* sizeof istream_withassign == 112 */
249 
250 # 493 "./iostream.h"
251 int x_gcount__7istream ;
252 
253 # 503 "./iostream.h"
254 struct __mptr *__vptr__7istream ;
255 struct ios *Pios;
256 struct ios Oios;
257 };
258 
259 # 644 "./iostream.h"
260 extern struct istream_withassign cin ;
261 
262 # 628 "./iostream.h"
263 struct ostream_withassign { /* sizeof ostream_withassign == 104 */
264 
265 # 610 "./iostream.h"
266 struct __mptr *__vptr__7ostream ;
267 struct ios *Pios;
268 struct ios Oios;
269 };
270 
271 # 645 "./iostream.h"
272 extern struct ostream_withassign cout ;
273 extern struct ostream_withassign cerr ;
274 extern struct ostream_withassign clog ;
275 
276 # 657 "./iostream.h"
277 struct Iostream_init { /* sizeof Iostream_init == 1 */
278 
279 # 657 "./iostream.h"
280 char __W23__13Iostream_init ;
281 };
282 
283 # 658 "./iostream.h"
284 extern int stdstatus__13Iostream_init ;
285 extern int initcount__13Iostream_init ;
286 
287 # 663 "./iostream.h"
288 char __dt__13Iostream_initFv ();
289 
290 # 662 "./iostream.h"
291 struct Iostream_init *__ct__13Iostream_initFv ();
292 
293 # 664 "./iostream.h"
294 static struct Iostream_init iostream_init ;
295 
296 #pragma lib "ape/libap.a"
297 
298 #pragma lib "c++/libC.a"
299 
300 #pragma lib "ape/libap.a"
301 
302 #pragma lib "c++/libC.a"
303 
304 # 20 "./generic.h"
305 typedef int (*GPT )();
306 
307 # 112 "./iomanip.h"
308 struct smanip_int { /* sizeof smanip_int == 16 */
309 
310 # 112 "./iomanip.h"
311 struct ios *(*fct__10smanip_int )();
312 
313 # 112 "./iomanip.h"
314 int arg__10smanip_int ;
315 };
316 
317 # 1 ""
318 extern char *__nw__FUl ();
319 
320 # 112 "./iomanip.h"
321 struct sapply_int { /* sizeof sapply_int == 8 */
322 
323 # 112 "./iomanip.h"
324 struct ios *(*fct__10sapply_int )();
325 };
326 
327 # 112 "./iomanip.h"
328 struct imanip_int { /* sizeof imanip_int == 16 */
329 
330 # 112 "./iomanip.h"
331 struct istream *(*fct__10imanip_int )();
332 
333 # 112 "./iomanip.h"
334 int arg__10imanip_int ;
335 };
336 
337 # 112 "./iomanip.h"
338 struct iapply_int { /* sizeof iapply_int == 8 */
339 
340 # 112 "./iomanip.h"
341 struct istream *(*fct__10iapply_int )();
342 };
343 
344 # 112 "./iomanip.h"
345 struct omanip_int { /* sizeof omanip_int == 16 */
346 
347 # 112 "./iomanip.h"
348 struct ostream *(*fct__10omanip_int )();
349 
350 # 112 "./iomanip.h"
351 int arg__10omanip_int ;
352 };
353 
354 # 112 "./iomanip.h"
355 struct oapply_int { /* sizeof oapply_int == 8 */
356 
357 # 112 "./iomanip.h"
358 struct ostream *(*fct__10oapply_int )();
359 };
360 
361 # 112 "./iomanip.h"
362 struct iomanip_int { /* sizeof iomanip_int == 16 */
363 
364 # 112 "./iomanip.h"
365 struct iostream *(*fct__11iomanip_int )();
366 
367 # 112 "./iomanip.h"
368 int arg__11iomanip_int ;
369 };
370 
371 # 112 "./iomanip.h"
372 struct ioapply_int { /* sizeof ioapply_int == 8 */
373 
374 # 112 "./iomanip.h"
375 struct iostream *(*fct__11ioapply_int )();
376 };
377 
378 # 112 "./iomanip.h"
379 
380 # 113 "./iomanip.h"
381 struct smanip_long { /* sizeof smanip_long == 16 */
382 
383 # 113 "./iomanip.h"
384 struct ios *(*fct__11smanip_long )();
385 
386 # 113 "./iomanip.h"
387 long arg__11smanip_long ;
388 };
389 
390 # 113 "./iomanip.h"
391 struct sapply_long { /* sizeof sapply_long == 8 */
392 
393 # 113 "./iomanip.h"
394 struct ios *(*fct__11sapply_long )();
395 };
396 
397 # 113 "./iomanip.h"
398 struct imanip_long { /* sizeof imanip_long == 16 */
399 
400 # 113 "./iomanip.h"
401 struct istream *(*fct__11imanip_long )();
402 
403 # 113 "./iomanip.h"
404 long arg__11imanip_long ;
405 };
406 
407 # 113 "./iomanip.h"
408 struct iapply_long { /* sizeof iapply_long == 8 */
409 
410 # 113 "./iomanip.h"
411 struct istream *(*fct__11iapply_long )();
412 };
413 
414 # 113 "./iomanip.h"
415 struct omanip_long { /* sizeof omanip_long == 16 */
416 
417 # 113 "./iomanip.h"
418 struct ostream *(*fct__11omanip_long )();
419 
420 # 113 "./iomanip.h"
421 long arg__11omanip_long ;
422 };
423 
424 # 113 "./iomanip.h"
425 struct oapply_long { /* sizeof oapply_long == 8 */
426 
427 # 113 "./iomanip.h"
428 struct ostream *(*fct__11oapply_long )();
429 };
430 
431 # 113 "./iomanip.h"
432 struct iomanip_long { /* sizeof iomanip_long == 16 */
433 
434 # 113 "./iomanip.h"
435 struct iostream *(*fct__12iomanip_long )();
436 
437 # 113 "./iomanip.h"
438 long arg__12iomanip_long ;
439 };
440 
441 # 113 "./iomanip.h"
442 struct ioapply_long { /* sizeof ioapply_long == 8 */
443 
444 # 113 "./iomanip.h"
445 struct iostream *(*fct__12ioapply_long )();
446 };
447 
448 # 113 "./iomanip.h"
449 
450 # 10 "./stdio.h"
451 typedef char *va_list ;
452 
453 # 118 "./stdio.h"
454 extern char *sys_errlist [];
455 extern int sys_nerr ;
456 extern unsigned char *_bufendtab [];
457 
458 # 22 "./stdiostream.h"
459 struct stdiobuf { /* sizeof stdiobuf == 96 */
460 
461 # 196 "./iostream.h"
462 short alloc__9streambuf ;
463 short x_unbuf__9streambuf ;
464 char *x_base__9streambuf ;
465 char *x_pbase__9streambuf ;
466 char *x_pptr__9streambuf ;
467 char *x_epptr__9streambuf ;
468 char *x_gptr__9streambuf ;
469 char *x_egptr__9streambuf ;
470 char *x_eback__9streambuf ;
471 int x_blen__9streambuf ;
472 
473 # 370 "./iostream.h"
474 struct __mptr *__vptr__9streambuf ;
475 
476 # 36 "./stdiostream.h"
477 struct _iobuf *fp__8stdiobuf ;
478 int last_op__8stdiobuf ;
479 char buf__8stdiobuf [2];
480 };
481 
482 # 21 "./fstream.h"
483 struct filebuf { /* sizeof filebuf == 120 */
484 
485 # 196 "./iostream.h"
486 short alloc__9streambuf ;
487 short x_unbuf__9streambuf ;
488 char *x_base__9streambuf ;
489 char *x_pbase__9streambuf ;
490 char *x_pptr__9streambuf ;
491 char *x_epptr__9streambuf ;
492 char *x_gptr__9streambuf ;
493 char *x_egptr__9streambuf ;
494 char *x_eback__9streambuf ;
495 int x_blen__9streambuf ;
496 
497 # 370 "./iostream.h"
498 struct __mptr *__vptr__9streambuf ;
499 
500 # 45 "./fstream.h"
501 int xfd__7filebuf ;
502 int mode__7filebuf ;
503 char opened__7filebuf ;
504 streampos last_seek__7filebuf ;
505 char *in_start__7filebuf ;
506 
507 # 51 "./fstream.h"
508 char lahead__7filebuf [2];
509 };
510 
511 # 23 "./fstream.h"
512 extern int openprot__7filebuf ;
513 
514 # 54 "./fstream.h"
515 struct fstreambase { /* sizeof fstreambase == 224 */
516 
517 # 72 "./fstream.h"
518 struct filebuf buf__11fstreambase ;
519 
520 # 75 "./fstream.h"
521 struct __mptr *__vptr__11fstreambase ;
522 struct ios *Pios;
523 struct ios Oios;
524 };
525 
526 # 87 "./fstream.h"
527 
528 # 70 "./fstream.h"
529 
530 # 141 "./iostream.h"
531 
532 # 70 "./fstream.h"
533 
534 # 77 "./fstream.h"
535 struct ifstream { /* sizeof ifstream == 248 */
536 
537 # 72 "./fstream.h"
538 struct filebuf buf__11fstreambase ;
539 
540 # 75 "./fstream.h"
541 struct __mptr *__vptr__11fstreambase ;
542 struct ios *Pios;
543 struct istream Oistream;
544 };
545 
546 # 102 "./fstream.h"
547 
548 # 70 "./fstream.h"
549 
550 # 141 "./iostream.h"
551 
552 # 70 "./fstream.h"
553 
554 # 92 "./fstream.h"
555 struct ofstream { /* sizeof ofstream == 240 */
556 
557 # 72 "./fstream.h"
558 struct filebuf buf__11fstreambase ;
559 
560 # 75 "./fstream.h"
561 struct __mptr *__vptr__11fstreambase ;
562 struct ios *Pios;
563 struct ostream Oostream;
564 };
565 
566 # 117 "./fstream.h"
567 
568 # 70 "./fstream.h"
569 
570 # 141 "./iostream.h"
571 
572 # 70 "./fstream.h"
573 
574 # 53 "./stream.h"
575 
576 # 54 "./stream.h"
577 
578 # 55 "./stream.h"
579 
580 # 56 "./stream.h"
581 
582 # 57 "./stream.h"
583 
584 # 58 "./stream.h"
585 
586 # 59 "./stream.h"
587 
588 # 60 "./stream.h"
589 
590 # 62 "./stream.h"
591 typedef int state_value ;
592 
593 # 571 "./iostream.h"
594 struct ostream *__ls__7ostreamFPCc ();
595 
596 # 3 "hello.C"
597 int main (){ _main(); 
598 # 4 "hello.C"
599 { 
600 # 5 "hello.C"
601 __ls__7ostreamFPCc ( (struct ostream *)(& cout ), (char *)"Hello, World!\n") ;
602 }
603 } 
604 # 6 "hello.C"
605 char __sti___main_ ()
606 # 664 "./iostream.h"
607 { __ct__13Iostream_initFv ( & iostream_init ) ;
608 
609 # 664 "./iostream.h"
610 }
611 
612 # 6 "hello.C"
613 char __std___main_ ()
614 # 664 "./iostream.h"
615 { __dt__13Iostream_initFv ( & iostream_init , 2) ;
616 
617 # 664 "./iostream.h"
618 }
619 
620 # 23 "./fstream.h"
621 int openprot__7filebuf ;
622 
623 # 56 "./iostream.h"
624 
625 # 659 "./iostream.h"
626 int initcount__13Iostream_init ;
627 
628 # 658 "./iostream.h"
629 int stdstatus__13Iostream_init ;
630 
631 # 180 "./iostream.h"
632 char (*stdioflush__3ios )();
633 
634 # 151 "./iostream.h"
635 long nextword__3ios ;
636 
637 # 150 "./iostream.h"
638 long nextbit__3ios ;
639 
640 # 88 "./iostream.h"
641 long floatfield__3ios ;
642 
643 # 86 "./iostream.h"
644 long adjustfield__3ios ;
645 
646 # 84 "./iostream.h"
647 long basefield__3ios ;
648 
649 # 6 "hello.C"
650 
651 /* the end */

只有這樣還不能滿足吧, 希望可以讓這個 c 檔案透過 gcc 編譯出可執行檔案, 這就會需要那個 libC.a 了, cout 在 libC.a 中。

上面那個是我自己亂試的, 後來我參考了 cfront-3/demo/hello/hello.sh, 知道整個使用 cfront 的編譯步驟。

cfront-3/demo/hello/hello.sh
 1 #!/bin/sh
 2
 3 # manual steps to compile a program
 4 # http://lists.nongnu.org/archive/html/tinycc-devel/2014-12/binCQHJXV7ywM.bin
 5 #
 6 # The CC script now work.
 7 # Anyway, here is how to compile a C++ file manually
 8
 9
10 D=../..
11
12 if [ ! -x ${D}/cfront ]; then
13     echo "error: cfront compiler not found"
14     exit
15 fi
16
17 cpp -I${D}/incl hello.C > hello.i                  # run preprocessor
18 ${D}/cfront +a1 +L +fhello.C < hello.i > hello..c       # run cfront
19 cc hello..c ${D}/libC.a -o hello.tmp                  # compile and link plain C
20
21 # For static con/destructors, the nm/munch thingy is needed
22
23 nm hello.tmp | ${D}/munch > hello.cdts..c  # run mn against linked binary and filter
24 cc hello..c hello.cdts..c ${D}/libC.a -o hello        # compile and link again
25
26 ./hello

我們來看看怎麼編譯在平常不過的 hello world c++ 程式。

hello.C
1 #include <stream.h>
2
3 main()
4 {
5     cout << "Hello, World!\n";
6 }

在 cfront-3 目錄中執行:
cpp -Iincl-master/incl-linux32/ hello.C > hello.i # 處理 header files
./cfront +a1 +L +fhello.C < hello.i > hello..c # 將 cpp 檔 (.C) 轉成 .c 檔
gcc hello..c ./libC.a -o hello.tmp # 不知道
nm hello.tmp | ./munch > hello.cdts..c # 不知道
gcc hello..c hello.cdts..c ./libC.a -o hello # 輸出可執行檔
./hello # 執行

看到印出來的 Hello, World 真是感動。

後來我測試了, template function, class template 都沒有問題。

用 cfront 編譯 cfront 時, alloc.C 遇到的問題:
CC3 L608
eval 'gcc -Du3b -U__GNUC__ -D__cfront__ -D__cplusplus=1 -D__signed__= -D__null=0 -E' ' -I../incl-master/incl-linux32/ -D__CFRONT_ANSI_OPT'  '-Dc_plusplus=1' '-D__cplusplus=1' '' ' -I/media/work/git/cfront-3/incl' 'alloc.C' \>/media/work/git/cfront-3/tmpdir/CC.25638/cpptmp

用 llvm 也可以作到 c++ 轉 c code, 參考 Can I use LLVM to convert C++ code to C code? 不過要 3.1 版才能用, 我的系統最低是 3.6。

不過 llvm 用的方式是先轉成 .bc 再將 .bc 轉成 c, 其實和 cfront 不太一樣。

ref:
[LLVMdev] How to enable cbe as a supported target?

至於很常用到的 vector, 這個版本付的 vector 用法和 std::vector 的用法很不同:

demo/generic/Vector.C
vectordeclare(int)
vectordeclare(float)

vectorimplement(int)
vectorimplement(float)
vector(int)     iv(VectorSize);

看起來很類似 macro 的用法, 而不是 class template 的用法, 後來將我那個 myvec.h 修改一下, 可以用在 cfront。

v.C
 1 #include <stream.h>
 2 #include "myvec.h"
 3 
 4 main()
 5 {
 6   vector<int> v;
 7   v.push_back(1);
 8   v.push_back(2);
 9   cout << v[0] << endl;
10   cout << v[1] << endl;
11 }

是可以用的。

ref:
另外一個 cfront 版本