您的位置:首页 > 编程语言 > C语言/C++

C/C++基础(三)【sizeof && inline函数】

2013-10-21 19:35 375 查看
sizeof
下面代码的输出结果是什么?
[整型 int 4字节

短整型 short 2字节

长整型 long 4字节

字符型 char 1字节

单精度 float 4字节

双精度 double 8字节

长双精度 long double 8字节

]

#include <iostream>

#include <stdio.h>

#include <stdlib.h>

using namespace std;

struct{

  short a1;

  short a2;

  short a3;

}A;

struct{

  long a1;

  short a2;

}B;

int main()

{

  char* ss1 = "0123456789";

  char ss2[] = "0123456789";

  char ss3[100] = "0123456789";

  int ss4[100];

  char q1[] = "abc";

  char q2[] = "a\n";

  char *q3 = "a\n";

  char *str1 = (char *)malloc(100);

  void *str2 = (void *)malloc(100);

  cout<<sizeof(ss1)<<" ";//4 指针就是一个地址值,在32位系统下,占用4个字节,

  cout<<sizeof(ss2)<<" ";//11   

  cout<<sizeof(ss3)<<" ";//100

  cout<<sizeof(ss4)<<" ";//400

  cout<<sizeof(q1)<<" ";//4

  cout<<sizeof(q2)<<" ";//3

  cout<<sizeof(q3)<<" ";//4

  cout<<sizeof(A)<<" ";//6

  cout<<sizeof(B)<<" ";//8

  cout<<sizeof(str1)<<" ";//4

  cout<<sizeof(str2)<<endl;//4

  return 0;

}

/*

jj@ubuntu:~/JJ$ ./testsizeof

4 11 100 400 4 3 4 6 8 4 4

*/

解析:
凡是指针的,指针的大小是一个定值,就是4字节,所以sizeof(ss1)是4字节

ss2 是一个字符数组,这个数组最初未定大小,由具体填充值来定。填充值是“0123456789”。1个字符所占空间是1字节,10个就是10字节,再加上隐含的"\0",所以一共是11字节。

ss3 也是一个字符数组,这个数组开始预分配100,所以它的大小一共是100字节。

ss4 也是一个整型数组,这个数组开始预分配100,但每个整型变量所占空间是4,所以它的大小一共是400字节。

q2里面有一个"\n","\n"算作1个字节,所以空间大小是3字节。

A和B是两个结构体。在默认情况下,为了方便对结构体内元素的访问和管理,当结构体内的元素的长度都小于处理器的位数的时候,便以结构提里面最长的数据元素为对齐单位,也就是说,结构提的长度一定是最长的数据元素的整数倍。如果结构体内存在长度大于处理器位数的元素,那么就以处理器的位数为对齐单位。但是结构体内类型相同的连续元素将在连续的空间内,和数组一样。[结构提默认的对齐参数按8字节对齐]

A中有3个short类型变量,各自以2字节对齐,结构体的对齐参数按默认的8字节对齐,则a1,a2,a3都取2字节,sizeof(A)为6,是2的整数倍。B中a1为4字节对齐,a2为2字节对齐,则a1取4字节,a2取4字节(按4字节对齐),则sizeof(B)为8.

数据对齐,是指数据所在的内存地址必须是该数据长度的整数倍。DWORD数据的内存起始地址能被4整除,WORD数据的内存起始地址能被2除尽。编译器在编译程序时尽量保证数据对齐,是为了提升运行速度。

以下代码为32位机器编译,数据是以4字节为对齐单位,这两个类的输出结果为什么不同?

class B

{

 private:

 bool m_bTemp;

 int m_nTemp;

 bool m_bTemp2;

};

class C

{

 private;

 int m_nTemp;

 bool m_bTemp;

 bool m_bTemp2;

};

考察点:字节对齐。

在VC中,我们可以用pack预处理指令来禁止对齐调整,使得结构尺寸更加紧凑,不会出现对齐到4字节问题。但不得已不要用,因为为降低程序性能。常见要用的情况是:1 这个结构需要被直接写入文件; 2 这个结构需要通过网络传给其他程序。

在本题中,第一种类的数据对齐是下面的情况:

bool --- --- ---

-------int------

bool --- --- ---

第二种类的数据对齐是下面的情况:

-------int------

bool bool--- ---

所以类的大小分别是3*4=12 和 2*4 = 8;

求解下面程序的结果

#include <iostream>

using namespace std;

class A1

{

 public:

 int a;

 static int b;

 A1();

 ~A1();

};

class A2

{

  public:

  int a;

  char c;

  A2();

  ~A1();

}

class A3

{

  public:

  float a;

  char c;

  A3();

  ~A3();

};

class A4

{

  public:

  float a;

  int b;

  char c;

  A4();

  ~A4();

};

class A5

{

  public:

  double d;

  float a;

  int b;

  char c;

  A5();

  ~A5();

}

因为静态变量是存放在全局数据区的,而sizeof计算栈中分配的大小,是不会计算在内的,所以sizeof(A1)是4。

为了照顾数据对齐,int大小为4,char大小为1,所以sizeof(A2)是8。

为了照顾数据对齐,float大小为4,char大小为1,所以sizeof(A3)是8。

为了照顾数据对齐,float大小为4,int大小为4,char大小为1,所以sizeof(A3)大小是12。

为了照顾数据对齐,double大小为8,float大小为4,int大小为4,char大小为1,所以sizeof(A3)是24。

说明sizeof 和 strlen之间的区别

(1)sizeof操作符的结果类型是size_t,它在头文件中的typedef为unsigned int 类型。该类型保证能容纳实现所建立的最大对象的字节大小。

(2)sizeof是运算符,strlen是函数。

(3)sizeof可以用类型做参数,strlen只能用char*做参数,且必须是以"\0"结尾的。sizeof还可以用函数做参数,比如:

short f();

printf("%d\n",sizeof(f()));

输出的结果是sizeof(short),即2。

(4)数组做sizeof的参数不退化,传递给strlen就退化为指针。

(5)大部分编译在编译的时候就把sizeof计算过了,是类型或是变量的长度。这就是sizeof(x)可以用来定义数组维数的原因:

char str[20]="0123456789";

int a=strlen(str);//10

int b=sizeof(str);//20

(6)strlen的结果要在运行的时候才能计算出来,用来计算字符串的长度,而不是类型占内存的大小。

(7)sizeof后如果是类型必须加括号,如果是变量名可以不加括号。这是因为sizeof是个操作符而不是个函数。

(8)当使用里一个结构类型或变量时,sizeof返回实际的大小。当使用一静态的空间数组时,sizeof返回全部数组的尺寸。sizeof操作符不能返回被动态分配的数组或外部的数组的尺寸。

(9)数组作为参数传给函数时传的是指针而不是数组,传递的是数组的首地址,如fun(char[8]),fun(char[])都等价于fun(char *)。在c++里传递数组永远都是传递指向数组元素的指针,编译器不知道数组的大小。如果想在函数内知道数组的大小,需要这样做:进入函数后用memcpy将数组复制出来,长度由另一个形参传进去。代码如下:

fun(unsigned char *p1, int len)

{

 unsigned char* buf = new unsigned char[len+1];

 memcpy(buf,p1,len);

}

(10)sizeof操作符不能用于函数类型,不完全类型或位字段。不完全类型指具有未知存储大小数据的数据类型,如未知存储大小的数组类型,未知内容的结构或联合类型,void类型等。

说明sizeof的使用场合。

(1)在动态分配一对象时,可以让系统知道要分配多少内存;

(2)便于一些类型的扩充,在windows中有很多结构类型就有一个专用的字段用来存放该类型的字节大小。

(3)由于操作数的字节数在实现时可能出现变化,建议在涉及操作数字节大小时用sizeof代替常量计算。

(4)如果操作数是函数中的数组形参或函数类型的形参,sizeof给出其指针的大小。

(5)用它可以看看某种类型的对象在内存中所占的单元字节。

void * memset(void * s, int c, sizeof(s));

(6)sizeof操作符的一个主要用途是与存储分配和I/O系统那样的例程进行通信:例如:void *malloc(size_t size), size_t fread(void * ptr, size_t size, size_t nmemb, FILE * stream)。

int **a[3][4]数组占据多大空间:  3*4*4 = 48;

找出下面程序的错误,并解释它为什么是错的?

#include<iostream>

#include <string>

using namespace std;

int main(int argc, char* argv[])

{

  string strArr1[] = {"Trend","Micro","Soft"};

  string *pStrArr1 = new string[2];

  pStrArr1[0] = "US";

  pStrArr1[1]="CN";

  for(int i=0;i<sizeof(strArr1)/sizeof(string);i++)

  cout<<strArr1[i];

  cout<<endl;

  for(int j=0;j<sizeof(pStrArr1)/sizeof(string);j++)

  cout<<pStrArr1[j];

  cout<<endl;

  return 0;

}

解析:sizeof(pStrArr1)是指针的大小,固定为4,又sizeof(string)为4,所以j<1;当然就只能输出一个了。应该改为:j<sizeof(*pStrArr1)*2;因为*pStrArr1指向的是数组成员的大小,再*2则为整个数组的大小。

写出下面sizeof的答案

#include <iostream>

#include <complex>

using namespace std;

class Base

{

public:

Base(){cout<<"Base-ctor"<<endl;}

~Base(){cout<<"Base-dtor"<<endl;}

virtual void f(int){cout<<"Base::f(int)"<<endl;}

virtual void f(double){cout<<"Base::f(double)"<<endl;}

virtual void g(int i=10){cout<<"Base::g()"<<i<<endl;}

void g2(int i=10){cout<<"Base::g2()"<<i<<endl;}

};

class Derived:public Base

{

  public:

  Derived(){cout<<"Derived-ctor"<<endl;}

  ~Derived(){cout<<"Derived-dtor"<<endl;}

  void f(complex<double>)

  {cout<<"Derived::f(complex)"<<endl;}

  virtual void g(int i=20)

  {cout<<"Derived::g()"<<i<<endl;}

};

int main()

{

  Base b;

  Derived d;

  Base* pb = new Derived;

  cout<<sizeof(Base)<<"tt"<<endl;

  cout<<sizeof(Derived)<<"bb"<<endl;

}

解析:运行结果如下:

jj@ubuntu:~/JJ$ ./sizeof

Base-ctor

Base-ctor

Derived-ctor

Base-ctor

Derived-ctor

4tt

4bb

Derived-dtor

Base-dtor

Base-dtor

求类base的大小。因为类base只有一个指针,所以类base的大小是4。Derive大小与base类似,所以也是4。

[运行机制及解析还有待理解!!]

以下代码输出结果是多少?

char var[10]

int test(char var[])

{

  return sizeof(var);

};

解析:因为var[]等价于*var,已经退化为一个指针,所以大小是4。

以下代码输出的结果是多少?

class B

{

 float f;

 char p;

 int adf[3];

};

cout<<" "<<sizeof(B);

解析:对齐原则,4+1+12 = 17,因为4的倍数,所以20。

一个空类占多少空间?多重继承的空类呢?

答:一个空类所占空间为1,单一继承的空类也为1,多重继承的空类空间还是1。涉及虚继承,因为虚继承涉及虚表(虚指针),所以占4。举例如下:

#include <iostream>

#include <memory.h>

#include <assert.h>

using namespace std;

class A

{

};

class A2

{

};

class B:public A

{

};

class C:public virtual B

{

};

class D:public A, public A2

{

};

int main(int argc, char *argv[])

{

  cout<<"sizeof(A): "<<sizeof(A)<<endl;

  cout<<"sizeof(B): "<<sizeof(B)<<endl;

  cout<<"sizeof(C): "<<sizeof(C)<<endl;

  cout<<"sizeof(D): "<<sizeof(D)<<endl;

  return 0;

}

运行结果如下:

jj@ubuntu:~/JJ$ ./sizeofclass

sizeof(A): 1

sizeof(B): 1

sizeof(C): 4

sizeof(D): 1

内联函数和宏的差别是什么?
内联函数和普通函数相比可以加快程序运行的速度,因为不需要中断调用,在编译的时候内联函数可以直接被镶嵌到目标代码中。而宏只是一个简单的替换。
内联函数要做参数类型检查,这是内联函数跟宏相比的优势。
inline是指嵌入代码,就是在调用函数的地方不是跳转,而是把代码直接写到那里去。对于短小的代码来说,inline可以带来一定的效率提升,而且和C时代的宏函数相比,inline更安全可靠。可是这个是以增加空间消耗为代价的。至于是否需要inline函数,就需要根据实际情况来取舍了。

inline一般只用于如下情况:

(1)一个函数不断地被重复调用。

(2)函数只有简单的几行,且函数内不包含for,while,switch语句。

一般小程序没有必要定义成inline,但如果要完成一个工程项目,当一个简单函数被调用多次时,则应该考虑用inline。

宏在C语言里极其重要,但在C++里用得少多了。关于宏的第一规则是绝不应该去使用它,除非你不得不这样做。几乎每个宏都表明了程序设计语言里,程序里或者程序员的一个缺陷,因为它将在编译器看到程序的正文之前重新摆布这些正文。宏也是许多程序设计工具的主要麻烦。所以,如果使用了宏,就应该只能从各种工具中得到较少的服务。
宏是在代码处不加任何验证的简单替代,而内联函数是将代码直接插入调用处,而减少了普通函数调用时的资源消耗。

宏不是函数,只是在编译前(编译处理阶段)将程序中有关字符串替换成宏体。
inline函数是函数,但在编译中不单独产生代码,而是将有关代码嵌入到调用处。

inline fac(float i){return i*i}; //没有写返回值的

printf("bb= %d",fac(8));          //调用时就是执行printf("bb=%d,8*8");
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  C++ sizeof