c++中的sizeof,可以通過以下宏定義實現。
1 #include <stdio.h> 2 3 #define sizeof_T(T) ((size_t)((T*)0+1)) ///求類型的大小 4 #define sizeof_V(T) ((size_t)(&T+1)-(size_t)(&T)) ///求變量的大小 5 6 int main() { 7 int a=1, b[3]={0}; 8 printf("這個類型大小:%d \n這個類型單個變量的大小:%d \n這個類型數組變量的大小%d\n", sizeof_T(int), sizeof_V(a), sizeof_V(b)); 9 return 0; 10 }
那么為什么可以這樣實現呢?
對於求類型大小的sizeof_T:
首先我們通過(T*)0得到一個指向00000000的指針,而且這個指針是int類型的,現在我們將這個指針+1。比如我們用一個int *p指針指向一塊new int[10]的地址,那么此時很顯然(p+1)-p==4而不是1,因為我們其實不是在地址上加1,而是讓指針向前前進了一步,而這一步就是T這個類型的大小,也就是我們求的其實是指針步長。
可以通過以下程序發現這個特點,然后我們將00000000位置的指針向前移動一步,很顯然,這個時候我們就得到了這個類型的大小。
1 #include <stdio.h> 2 #include <iostream> 3 using namespace std; 4 int main() { 5 char *p=new char[10]; 6 int *q=new int[10]; 7 printf("%p %p\n%p %p\n", p, p+1, q, q+1); 8 delete p; 9 delete q; 10 return 0; 11 }
對於求變量大小的sizeof_V:
也是利用了指針步長的原理,這里值得注意的有兩點.
一是因為這里我們不是類型,所以說不可能定義一個指向0的指針,只能將自己的地址拿來運算。
二是數組名有一個特性,對於int p[10];這個數組,&p+1的值並不是數組首地址加上指針步長,此時的步長是數組本身,也就是一步跨越了整個數組。
第二點可以通過以下程序來驗證
1 #include <stdio.h> 2 int main() { 3 int p[3]; 4 printf("%p %p\n", p, &p+1); 5 return 0; 6 }
所以由以上特性我們就可以手動實現sizeof的功能了,說白了就是求指針步長。
我們既然知道了對數組來說&T+1相當於一步跨過整個數組,那么這是為什么呢,我由自己的做出相應的猜測,如有錯誤請在評論區指出。
對於int p[10];這個數組來說&p和什么相等呢?我測試的結果是&p==p[][10],也就是&p等於一個二維數組的數組名。也就是相當於將p提高了一個維度,原因就是如下的代碼:
#include <stdio.h> int main() { int p[2][2], T[2]; printf("%p %p\n%p %p\n", p, p+1, T, &T+1); return 0; }
在運行了代碼后你會發現p+1和&T+1的步長都是8。
那么其實就是對於數組,我們將他本身作為一個變量類型,就是相當於int [10]是一個變量類型。
再次感受到了那些大佬們的牛逼。