2018年5月26日 星期六

[娃衣] cheerydoll 廠家的娃衣 - (Limited) Lolita Mini Dress Set - gold

cheerydoll 是一間製作娃衣的廠商, 看起來像是韓國廠家, (Limited) Lolita Mini Dress Set - gold 這件吸引了我的目光。

金色馬甲是其中最讓我感興趣的元素, 目前總共有 3 件馬甲系列的服裝 (含這件)

20180302 註冊之後便訂購, 付款方式不是我習慣的信用卡, 而是 paypal, 我都幾乎忘記 paypal 了, 他的手續費用很高, 我不喜歡用 paypal 付款, 不過 cheerydoll 只提供這個國外付款方式。

沒辦法, 先去把我那個 paypal 綁定新的信用卡, 舊的那張已經過期了。

網站會發給你訂購資訊, 並在 24 小時之內發出 paypal 付款的請求信件, 如 fig 1 左圖那樣, fig 1 右圖則是用 paypal 付完款之後的訊息。

142.86 us 是衣服價錢, 15 us 是國際運費。

fig 1
 

Ordering Information
Image
Product Name
Price
Quantity
Total
 (Limited) Lolita Mini Dress Set -gold
 (Limited) Lolita Mini Dress Set -gold

 size DD-L
15,152円
$142.86 
15,152円
$142.86
 

fig 2. paypal 不好的匯率
透過 email 之中的連結就會轉到 paypal 付款頁面, fig 2 是 paypal 預設的付款匯率, 很差, 我選用「透過發卡方兌換」實際付出 4703 台幣, 還好有先查了一下。



選用「透過 paypal 兌換」要付 4821, 足足多了 118 台幣, 這讓我對 paypal 印象又更差了。

paypay 會紀錄卡片所有資訊, 包含背後那 3 個號碼, 其中的風險請自己評估, 我會用 paypal 純屬無可奈何, 這個小店家, 可能沒有滿足可以使用信用卡付款的條件, 所以只能選擇用 paypal 來收款。

付款之後會有一封電子郵件說你已經付款, 不過是韓文寫的。

這個網站用英文和我溝通, 用韓文通知已付款, 用日文通知寄送出物品了, 3 個語言用的很好很滿, 好在有 google translate, 難不倒我的。

在訂購之前, 已經問過其他娃友, 有人買過這家的娃衣嗎? 答案是肯定的, 所以應該是正當經營的店家, 心裡也比較放心, 畢竟這是比大數目, 出問題的話還是會心疼的。

在等待的期間, 我覺得有點久了, 便發了封電子郵件問問目前的進度, 店家回應蠻快的, 說明大概什麼時候會寄出, 我至少安心點了, 畢竟沒有交易過, 不知道會不會有問題, 錢付了, 收不到貨品, 這可是垂心肝的痛阿!

韓文已付款訊息

결제정보전송


Inbox
x

체리돌 scott3004@naver.com

Mar 3
to me
주문번호[201803022143348928] 결제완료

fig 3. 20180302 註冊/訂購, 20180303 paypal 付款, 20180319 寄出, 20180322 收到


店家寄出之後, 會給寄件編號, 20180319 寄出, 20180322 收到, 速度還蠻快的, 我還以為要 2 個禮拜才能收到, 還沒查寄件編號目前到哪裡了, 完全沒有任何心裡準備下, 突然就收到了。

趕緊打開, 看看那件精緻的馬甲, 訂購的是 DD L 胸的, 覺得馬甲還是胸大點比較好看。



金色看起來格外華麗, 作工果然精緻, 綁繩的洞洞不會刮傷素體, 之前買到一件類似的衣服, 其洞洞用的零件會刮傷素體, 讓我心痛了一下, 除此之外, 還多縫了一塊布料, 蓋住綁繩的部份。

短裙除了本體之外, 還多了一塊尾巴, 類似婚紗的澎澎裙, 我不是很喜歡這個部份, 還好可以分離, 這是以別針的方式夾住, 就先來個輕裝打扮吧!





下圖則是另外的配件, 更改手上和脖子肩膀的服飾, 一件套裝, 2 種穿法。



在淘寶上找到了金色鞋子, 看起來很搭, 全身金光閃閃, 應該不俗氣吧!

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 */