Call by value? Call by reference? Call by address to pointer? call by NAME ? 1 void foo(long x, long&y, long*k) { // long : l, long& : Rl, long* : Pl 2 static long aaaX, aaaY, aaaKKK; // 靜態變數會被偷改名稱 3 static long aaaZZZ = k[0]; // same as *k 4 aaaX = x; aaaY = y; aaaKKK = *k; // 你可自己印出各值看看 5 } 6 long bbb = 49; // Global 變數, 初值放 49 7 void haha( ) { // 自己寫一個 main( ) 來叫用 haha( ); 試試 8 foo(38, bbb, &bbb); // call by value, reference, address to pointer 9 foo(bbb, bbb, &bbb); // value, reference, address to pointer 10 } // 多數C++ compiler 其實偷用 call by address to pointer做出call by Reference 11 // 因此此例中對於 aaaY = y; 和 aaaKKK = *k; 翻譯出的會相同 12 D:\COURSE\OOP\ppnt>g++ -S cvr.cpp ; 就是 參數 long&y 會被偷換成 long*y 13 ;;; 且該函數內所有 y 都會被偷換成 *y 14 D:\COURSE\OOP\ppnt>type cvr.s ;; 另外叫用該函數 foo(bbb,bbb, &bbb); 15 .file "cvr.cpp" ;; 會被偷改成 foo(bbb,&bbb, &bbb); 16 .lcomm __ZGVZ3foolRlPlE6aaaZZZ,16 ;; 以下是 foo(long,long&,long*)內靜態變數 17 .lcomm _ZZ3foolRlPlE4aaaX,16 ;; 上列是FLAG管制讓 aaaZZZ = k[0]; 只做一次 18 .lcomm _ZZ3foolRlPlE4aaaY,16 ;; 因 aaaZZZ 是static local只可初始化一次 19 .lcomm _ZZ3foolRlPlE6aaaKKK,16 ;; .lcomm 表示要放 .bss section 20 .lcomm _ZZ3foolRlPlE6aaaZZZ,16 ;; ..., 16 表示要保留 16 bytes 21 .text 22 .align 2 ;; 程式碼必須放在除以 2 除得盡的 address 23 .globl __Z3foolRlPl ;; lRlPl 代表 l: long, Rl: long&, Pl: long* 24 .def __Z3foolRlPl; .scl 2; .type 32; .endef 25 __Z3foolRlPl: ;; void foo(long x, long&y, long*k) { 26 pushl %ebp ;; save OLD eBP 27 movl %esp, %ebp ;; eBP = eSP; 讓 eBP 也指到 Stack 此時頂端 28 cmpb $0, __ZGVZ3foolRlPlE6aaaZZZ ;;static local 只一次設初值 29 jne L2 ;; 若已經做過則 goto L2 30 movl 16(%ebp), %eax ;; 抓第3個參數 k 到 EAX 31 movl (%eax), %eax ;; copy mem[EAX] 到 EAX 32 movl %eax, _ZZ3foolRlPlE6aaaZZZ ;; 把EAX 放入 aaaZZZ 33 movb $1, __ZGVZ3foolRlPlE6aaaZZZ ;; 設 flag 以便表示已經做過 34 L2: ;; 若第2次或以後叫用則跳過上述設 aaaZZZ 初值的動作 35 movl 8(%ebp), %eax ;;抓第一個參數 x 36 movl %eax, _ZZ3foolRlPlE4aaaX ;; 直接塞入 aaaX 37 movl 12(%ebp), %eax ;抓第2個參數 y, 是address, 因是 by Reference 38 movl (%eax), %eax ;; eax = mem[eax]; 就是原來的 eax 是位址 39 movl %eax, _ZZ3foolRlPlE4aaaY ;; 存入 aaaY 40 movl 16(%ebp), %eax ;; 抓第3個參數 k 到 EAX, 是 address 41 movl (%eax), %eax ;; EAX = memory[EAX]; 即 *k 42 movl %eax, _ZZ3foolRlPlE6aaaKKK ;; 存入 aaaKKK 43 popl %ebp ;; recover OLD EBP 44 ret ;; 注意參數一 在 [%ebp+8], 參數2 在 [%ebp+12], 參數3在[%ebp+16] 45 .globl _bbb ;; 宣告 _bbb 是 Global public 46 .data ;; 所有 .data 的都會被 Linker 自動串在一起放 47 .align 4 ;; long 須放除以 4 除得盡之 address 48 _bbb: ;; 此處就是 Global 變數 bbb 49 .long 49 ;; compile 時就放 49 (static binding) 50 .text ;; 所有 .text 的都會被自動連著放 51 .align 2 52 .globl __Z4hahav ;; 宣告 haha(void) 是 Global public 53 .def __Z4hahav; .scl 2; .type 32; .endef 54 __Z4hahav: ;; 7 void haha( ) { 注意 haha右邊的 v 是說參數 void 55 pushl %ebp ;; function 的 return type 不會在名稱中 56 movl %esp, %ebp ;; 書上說 return type 不在 signature 中 57 subl $12, %esp ;; 挪出 12 bytes空間以便推入參數準備叫 foo( ) 58 movl $_bbb, 8(%esp) ;; 把 address of bbb 塞到 [eSP+8], 傳給 k 59 movl $_bbb, 4(%esp) ;; 還是 &bbb, 塞到 [eSP+4], 傳給 y 60 movl $38, (%esp) ;; 最上面是 (long)38, , 傳給 x 61 call __Z3foolRlPl ;; foo(38, bbb, &bbb); 第二和第三處理方式相同! 62 ;;; 這是因 C++ 偷改程式用 call by address to pointer做出 call by Reference 63 movl $_bbb, 8(%esp) ;; 先推 &bbb 64 movl $_bbb, 4(%esp) ;; 還是 &bbb 65 movl _bbb, %eax ;; EAX = Content of bbb 注意不是 addr 66 movl %eax, (%esp) ;; 放堆疊頂端 67 call __Z3foolRlPl ;; foo(bbb, bbb, &bbb); 68 leave ;; clear Stack and do some housekeeping jobs 69 ret ;; 其實 leave === copy %ebp to %esp, then popl %ebp