sizeof()的各种类型大小

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

#include <iostream>
#include <stdio.h>
#include <string.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;
}

凡是指针的,指针的大小是一个定值,就是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--- ---
所以类的大小分别是34=12 和 24 = 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]数组占据多大空间: 344 = 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;}
};</complex></iostream>

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;}
};</double>

int main()
{
Base b;
Derived d;
Base* pb = new Derived;
cout<<sizeof(Base)<<"tt"<<endl;
cout<<sizeof(Derived)<<"bb"<<endl;
}
解析:运行结果如下:
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;
}

运行结果如下:

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 ii}; //没有写返回值的
printf("bb= %d",fac(8)); //调用时就是执行printf("bb=%d,8
8");

全部评论

相关推荐

点赞 收藏 评论
分享
牛客网
牛客企业服务