天天看點

c++ sizeof的實作

在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的功能了,說白了就是求指針步長。