烦人的sizeof

大家是否发现sizeof好多什么很烦人。。老是弄错的时候。实在没办法了。。对它做下总结吧。。希望以后少出错。。

1 sizeof 是什么?

   sizeof()不是函数,不是宏。它是一个关键字。一个运算符。

2 sizeof用来干什么?

  sizeof()他可以获得一中数据类型(内置类型或自定义类型)或一个变量所占字节的大小。结果为一个十进制数。

3 sizeof()和strlen()的区别。

  现在我们知道sizeof是一个运算符了。那strlen是什么呢?我们去MSDN上看下:

Code:
  1. size_t strlen( const char *string );   
  2. size_t wcslen( const wchar_t *string );  

这是MSDN的结果。也就是说strlen()是一个函数,返回类型为size_t。参数为const char *.好。我们明白了,下面我们看几个例子来区分一下吧:

第一个例子:

Code:
  1. char * p = "123456";   
  2. cout << sizeof(p) << endl;// 结果为4   
  3. cout << sizeof(*p) << endl;//结果为1   
  4. cout << strlen(p) << endl;//结果为6   

首相记住一句话,所有指针(包括void*)所占的大小均为4个字节。故第一个结果为4。这点到令我想起了类。我们知道在一个类未定义完成之前我们是无法用它来定义对象的。然而我们可以用它来定义指针成员。为什么呢?因为当我们用一个类型来定义对象时。我们在编译时必须知道这个类型的大下,该为此对象非配多大的空间。而此时我们的类并没有定义完整,编译器是无法得知类的大小的。故也就无法为该类的对象分配空间。故就干脆禁止定义类对象。而指针就不同了。因为任何类型的指针大小均为4.故编译器一看到指针直接分配4个字节就对了。。呵呵。。

程序的第二行结果为1,因为指针p中存放的是字符串的首地址。即字符串第一个字符的地址。*p也就是字符串第一个字符。类型为char故结果为1.

第三行strlen是用来求字符串的长度,不含结束符"/0";故结果为6

第二个例子:

Code:
  1. char a[100] = "123456";   
  2. cout << sizeof(a) << endl; //结果为100   
  3. cout << strlen(a) << endl; // 结果为6  

第一行:结果为100.是因为在我们定义字符数组时,下标标出了100,此时编译器就会为我们分配100*sizeof(char)的内存空间。

第二行:结果类似第一个例子,是对该数组求长度。

第三个例子:

Code:
  1. char a[] = "123456";   
  2. cout << sizeof(a) << endl; //结果为7   
  3. cout << strlen(a) << endl; //j结果为6   

第一行:结果为7,是因为编译器在为数组分配空间时,看到数组a中没有标下标,故就根据后面字符串的长度来为该数组分配空间。而后面字符串的长度为7(包括结束符"/0"),故结果为7;

第四个例子:

Code:
  1. int a[100] = {1,2,3};   
  2. cout << sizeof(a) << endl; //结果为400   
  3. cout << strlen(a) << endl; //错误  

第一行:由于a是int行数组,故结果为100*sizeof(int).

第二行之所以错误是因为我们的strlen是个函数,它的参数是const char*。

4 sizeof的怪用

sizeof可以做数组的下标使用,作用类似于我们C++中的const。类似C中的define。呵呵。不知道吧。。我们看个例子:

Code:
  1. int a[sizeof(int)] = {1,3,4,5};  

编译下,成功了。。呵呵。。若是我们改成下面这样:

Code:
  1. int a[sizeof(int)] = {1,3,4,5,6,7};  

错误:too many initializers

为什么会成功呢?因为sizeof在编译的时候就被计算过了。。呵呵

5 牵涉到特殊字符时候的sizeof计算

 这里的特殊字符指那些类似 '/n','/t','//','/0'的东西。记住遇到这些东西的时候,把它当做1计算就对了。。如:

Code:
  1. char a[] = "b/n";   
  2. cout << sizeof(a) << endl; //结果为3  

6 牵涉到函数的sizeof

这里有两种含义,一种是对函数求sizeof。

这就怪了,我刚才还说sizeof仅对数据类型或变量求值的。呵呵。。其实这并没有违背我刚刚才的话。我们看下面例子:

Code:
  1. double f();   
  2. cout << sizeof(f()) << endl; //结果为8  

我们定义了一个函数f(),然后对它进行sizeof.还得出了结果。其实这里sizeof是对函数的返回类型进行了求值。因为f()的返回类型为double类型。故结果为8.

第二种函数,对函数里面的变量求值。

啊?函数里面的变量和其他的变量不一样?呵呵。一样的。不过有些变量传进来之后会改变身份的。。我们看下面例子:

Code:
  1. #include <iostream>   
  2. using namespace std;   
  3. void f(char a[]);   
  4. int main()   
  5. {   
  6.     char a[] = "123456";   
  7.     f(a);   
  8.     return 0;   
  9. }   
  10. void f(char a[])   
  11. {   
  12.     cout << sizeof(a) << endl; //结果为4   
  13.     return 0;   
  14. }  

结果为什么成4了呢。不该是7吗?这是因为a传进函数之后就退化成一个指针了。

7 牵涉到结构体的sizeof

这里就要考虑的东西多了,牵涉到结构体对齐,数据对齐问题了。很是烦人。

但是我们可以不然编译器进行结构体对齐:

我们使用这个#pragma pack(n)。n为指定的对齐数。当n==1时。这时候结构体便不再老老实实的输出实际的字节长度了。如:

Code:
  1. #include <iostream>   
  2. using namespace std;   
  3. #pragma pack(1)   
  4. struct stu   
  5. {   
  6.     char c;   
  7.     int a;   
  8. };   
  9. int main()   
  10. {   
  11.     cout << sizeof(stu) << endl;   
  12.     return 0;   
  13. }  

输出结果为5.当我们去掉:#pragma pack(1)后,结果为8。

如果我们改下n的值为2.此时运行结果为6.

n的值为3 时。哇!!编译器给出警告了。。说n的值只能是 1, 2 ,4, 8 ,16.

n的值为4时,结果为8.

n的值为8时,结果为8

n的值为16时。结果为8.

由此我们可以总结出一下几点:

①: 编译器是根据 #pragma pack(n) 中n的值和当前对象进行比较进行字节对齐的。

②:当 :#pragma pack(n) 中n的值大于等于结构体中最大长度变量时。n值将不再起作用。此时编译器将根据最大长度值和当前变量进行字节对齐。

 ③ 当我们的n值为1时。将不进行任何的补齐。输出实际的变量大小之和。

我们用的win32操作系统默认的应该是8字节对齐的即n== 8;所以我们平时考虑字节对齐时只需跟句最大变量进行对齐即可:

这里的规则大家可以参考资料:

http://space.itpub.net/14805538/viewspace-483697

http://www.diybl.com/course/3_program/c++/cppjs/20090403/163712.html

这些都是google出来的。大家若是想了解更对的东西不妨也google一下吧。

另外除了结构体对齐的原因需要考虑外,千万别忘了有些变量是不再sizeof的计算范围之内的。如:

静态变量。enum。union。

Code:
  1. #include <iostream>   
  2. using namespace std;   
  3. #pragma pack(16)   
  4. struct stu   
  5. {   
  6.  char c;   
  7.  static long double a;   
  8.  union t   
  9.  {   
  10.     int a;   
  11.     int b;   
  12.  };   
  13.  enum weekday{Monday};   
  14. };   
  15. int main()   
  16. {   
  17.     cout << sizeof(stu) << endl; //结果为1   
  18.     return 0;   
  19. }  

8 牵涉到类的sizeof

这个就更麻烦了。。不但要考虑到结构体对齐问题,还要考虑虚函数,虚继承等等。在类里除了结构体中提到的那些不占空间外,普通函数也是不占空间的。至于这里的sizeof就不再总结了。太多了。大家可以google下。呵呵。。

9 其他的sizeof

 有关标准库的sizeof你试过吗?如是没有的话,不妨可以去了解下哦。。呵呵。。

Code:
  1. cout << sizeof(string) << endl;   
  2. cout << sizeof(vector<int>) << endl;   
  3. cout << sizeof(vector<string>) << endl;   
  4. cout << sizeof(list<int>) << endl;   
  5. cout << sizeof(deque<int>) << endl;      
  6. string str[] = {"hello","world","nihao"};   
  7. cout << sizeof(str)/sizeof(string) << endl;   
  8. string *pstr = new string[2];   
  9. cout << sizeof(pstr)<< endl;  

若是有时间的话,上面的这些还是运行下看下结果呗。。呵呵。。了解一下。。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值