#define getNumberInArray(a) \ (sizeof(a) / sizeof(a[0]))這是相當常見的 C/C++ 技巧,但越是簡單的東西,越容易令人忽略細節,我們就來看看在不同語言層面中,sizeof 會有什麼差異。在 ANSI C 規格中,sizeof(char) 被嚴格定義為 1 個 size_t,所以考慮以下程式碼:
#include <stdio.h> int main() { printf("%d, %d\n", sizeof('J'), sizeof(char)); return 0; }輸出會是什麼呢?編譯並執行看看:
$ gcc -o sizeof sizeof.c $ ./sizeof 4, 1第二項的輸出 "1" 乃是依據 ANSI C 規格,不過第一項就比較有意思,當我們用 C++ compiler 重新編譯並執行時:
$ g++ -o sizeof sizeof.c $ ./sizeof 1, 1所以同樣是 sizeof('J'),在 C 與 C++ 語言就有不同的表徵,C++ 設計的本意是與 ANSI C 相容,但實際上存在些微的差異,這裡就是一個好例子。我們可從以上輸出得知,C++ 中 sizeof('J') 等同於 sizeof(char),所以我們看到輸出 "1",但是對於 C 語言來說,有著 "default to int" 的語意,所以等同於計算 sizeof(int),又在 32-bit 硬體架構來說,大致會輸出 "4",而 C# 與 C++ 對此有類似的表現,不過還是得考慮 sizeof('x') 或 sizeof(L'x') 的不同行為 (多國語文的 multi-character)。
#include <stdio.h> struct Empty { } empty; int main() { printf("sizeof(empty) = %d\n", sizeof(empty)); return 0; }先用 C compiler 編譯並執行:
$ gcc -o sizeof sizeof2.c $ ./sizeof sizeof(empty) = 0計算一個沒有內容的 struct,其 sizeof 為 "0",似乎很合理,那麼 C++ 呢?
$ g++ -o sizeof sizeof2.c $ ./sizeof sizeof(empty) = 1奇怪,GNU G++ 竟然輸出 "1",這是為什麼呢?依據 Standard C++ language definition 的說法:
struct Bar { };
struct Foo {
struct Bar a[2];
struct Bar b;
};
Foo f;
我們可以發現,在 f 這個 object 的 member:a 與 b,如果 sizeof(Bar) = 0,那麼 f.a[] 與 f.b 是否就有相同的 address 呢?為了避免歧異性,C++ 標準審議委員決定禁止 zero-sized addressable objects 的存在,所以基於 C++ 技術上考量,freestanding objects 必須有 non-zero size (非零大小),這是 C 與 C++ 語言層面的差異之一。的確是個很難注意的陷阱...不過jserv會用c#啊!
由 k3 發表於 February 12, 2007 08:57 PMTo k3
哈哈,我猜跟 Mono Project 有關。
喔喔! 原來有這樣的陷阱! 真是長見識 -.-
由 Eason 發表於 February 13, 2007 11:59 AM考慮 typeof(Bar) == 0, 遇到這種狀況會怎樣?
struct Bar { };
...
Bar b[20];
Bar *i = b, *j = b+20; /* i == j ?? */
...
上了一課,不過想問 Jserv :「這篇文章是否可以給我轉貼?」
由 PingLunLiao 發表於 February 13, 2007 09:44 PM@Palatis:
test.c:
--
#include
typedef struct { } Bar;
int main()
{
Bar b[20];
Bar *i = b, *j = b+20; /* i == j ?? */
printf("sizeof(b) = %d\ni = %d\nj = %d\n", sizeof(b), i, j);
return 0;
}
--
J:\>gcc test.c
J:\>a
sizeof(b) = 0
i = 2293596
j = 2293596
J:\>g++ test.c
J:\>a
sizeof(b) = 20
i = 2293576
j = 2293596