※ 引述《Hazukashiine (恥ずかしい ね...(>///<))》之銘言:
: b 跟 &b 的地址不一樣,簡單地說, &b 的地址並不存在,而且對編譯器來說是非法的。
: 因為當你在寫單獨一個 b 的時候, b 已經被隱式轉換成指標型態,而且這是被強制的。
: 在且 b 是一個右值(r-value),意思是你不能對此作取址的動作。
: 根據 ISO 文件 §4.2.1 Standard Conversions: Array-to-pointer conversion
: An lvalue or rvalue of type "array of N T" or "array of unknown bound of T"
: can be converted to an rvalue of type "pointer to T." The result is a pointer
: to the first element of the array.
: 接下來的第三個也是一樣,
: 陣列名稱有佔空間嗎?結果呼之欲出,當然不佔。因為陣列名稱(b)是右值,並不佔空間。
: 可是你一定會很好奇不佔空間的話你的程式要如何知道陣列在哪?
: 這件事很妙,站在C語言的角度並不佔空間,但是實作上辦不到,所以當然要佔空間。
: 只是這個變數不是你的程式可以 access 的,它被編譯器巧妙地包裝了。
不用爭論了,反正下面三件事情結果都是一樣的:
#include <stdio.h>
int main()
{
int a[5];
printf("&a[0]\t%p\n", &a[0]);
printf("a\t%p\n", a);
printf("&a\t%p\n", &a);
return 0;
}
執行結果:
&a[0] 0018FF48
a 0018FF48
&a 0018FF48
反組譯奉上:
.text:004011E8 push ebp
.text:004011E9 mov ebp, esp
.text:004011EB add esp, 0FFFFFFECh
.text:004011EE lea eax, [ebp-14h] ; 是這樣
.text:004011F1 push eax ; &a[0]
.text:004011F2 push offset aA0P ; "&a[0]\t%p\n"
.text:004011F7 call 00403DA8 ; 前往 printf
.text:004011FC add esp, 8
.text:004011FF lea edx, [ebp-14h] ; 一樣
.text:00401202 push edx ; a
.text:00401203 push offset aAP ; "a\t%p\n"
.text:00401208 call 00403DA8 ; 前往 printf
.text:0040120D add esp, 8
.text:00401210 lea ecx, [ebp-14h] ; 還是一樣
.text:00401213 push ecx ; &a
.text:00401214 push offset aAP_0 ; "&a\t%p\n"
.text:00401219 call 00403DA8 ; 前往 printf
.text:0040121E add esp, 8
.text:00401221 xor eax, eax
.text:00401223 mov esp, ebp
.text:00401225 pop ebp
.text:00401226 retn
由於 a is an array of 5 int,
又 sizeof(int) = 4,
故 sizeof(a) = 5 * 4 = 20 跟ASM中的[ebp-0x14]符合,
add esp, 0FFFFFFECh 又 相當於 sub esp, 0x14
反正這個 array 會放在 stack,
會擔心找不到位址嗎?
編譯器都安排好一切了,
結案。
題外話我後來用MSVC CL沒有其他參數下編譯後,
&a[0]的部分反組譯結果是
.text:00401010 mov eax, 4 ; sizeof(int) = 4
.text:00401015 imul ecx, eax, 0 ; 0 elements
.text:00401018 lea edx, [ebp+ecx-18h]
有趣的是這樣比較貼近原始的意義,
是透過陣列元素型態的大小(4)和數量(0)來算所需的偏移量(ecx)。