c++ sizeof用法,c中sizeof的用法

  c++ sizeof用法,c中sizeof的用法

  sizeof运算符的作用是返回对象或类型名称的长度(以字节为单位)。

  返回值的类型是标准库命名为size_t的类型,size_t类型是在cstddef的头文件中定义的,cstddef是C标准库的头文件stddef.h的C版本。他是一个有同情心的人

  机器的相关无符号类型,足够大以保证内存中对象的大小。

  1.sizeof是什么?

  首先,看看msdn上sizeof的定义:

  sizeof关键字给出与变量或类型(包括聚合类型)相关联的存储量,以字节为单位。该关键字返回size_t类型的值。

  看到return这个词,你会想到一个函数吗?不对。sizeof不是一个函数。你见过函数传递参数不带括号的吗?Zeof可以,所以sizeof不是函数。网上有人说sizeof是一元运算符,但我不这么认为,因为sizeof更像是一个特殊的宏,在编译阶段就被求值。例如:

  cout sizeof(int)endl;//32位计算机上int的长度为4

  cout sizeof(1==2)endl;//==运算符返回bool类型,相当于cout sizeof(bool)endl;

  已经被翻译成:

  int a=0;

  cout sizeof(a=3)endl;

  cout a endl

  为什么输出的是4,0而不是预期的4,3?在于sizeof在编译阶段的处理特点。因为sizeof不能编译成机器码,所以sizeof范围内的内容,也就是()不能被编译,而是被替换成一个类型。=运算符返回左操作数的类型,因此a=3等效于int,代码也替换为:

  int a=0;

  cout 4 endl

  cout a endl

  所以sizeof是不可能支持链表达式的,和一元运算符不一样。

  结论:不要把sizeof当成一个函数或者一元运算符,而是当成一个特殊的编译器预处理。

  2.sizeof的用法

  Sizeof有两种用法:

  (1)sizeof(对象)

  也就是说sizeof是用于对象的,也可以写成sizeof对象的形式。

  (2)sizeof(类型名)

  也就是说,对类型使用sizeof。注意,在这种情况下,编写sizeof typename是非法的。这里有几个例子来说明:

  int I=2;

  cout sizeof(I)endl;//sizeof(object)的用法是合理的。

  cout sizeof i endlsizeobject的用法是合理的

  cout sizeof 2 endl//2解析成int类型对象,sizeobject的用法合理。

  cout sizeof(2)endl;//2解析成int类型对象,用法对象,sizeof(object)合理。

  cout sizeof(int)endl;//sizeof(typename)的用法合理。

  int endl的cout sizeof//错误!对于运算符,请确保添加()

  可见加()永远是正确的选择。

  结论:不管sizeof要看重谁,最好加上()。

  3.数据类型的大小

  (1)C固有数据类型

  32位C中的基本数据类型,即char、short int (short)、int、long int (long)、float、double、long double。

  尺码有:1,2,4,4,4,8,10。

  考虑以下代码:

  cout sizeof(unsigned int)==sizeof(int)endl;//等于,输出1

  无符号只影响最高位的含义,数据长度不会改变。

  结论:无符号不能影响sizeof的值。

  (2)自定义数据类型

  Typedef可用于定义c #自定义类型。考虑以下问题:

  typedef短词;

  typedef长DWORD

  cout(sizeof(short)==sizeof(WORD))endl;//等于,输出1

  cout(sizeof(long)==sizeof(DWORD))endl;//等于,输出1

  结论:用户定义类型的sizeof值等于其原始类型。

  (3)功能类型

  考虑以下问题:

  int f1(){ return 0;};

  double F2(){ return 0.0;}

  void f3(){}

  cout sizeof(f1())endl;//f1()返回一个int,所以被认为是int。

  cout sizeof(F2())endl;//f2()返回一个double值,所以被认为是double。

  cout sizeof(F3())endl;//错误!Sizeof不能用于void类型。

  cout sizeof(f1)endl;//错误!Sizeof不能用于函数指针。

  cout sizeof * f2 endl//*f2,相当于f2(),不需要,因为它可以看作一个对象。被视为双精度。

  结论:对函数使用sizeof,在编译阶段会被函数返回值的类型所替代。

  4.指针问题

  考虑以下问题:

  cout sizeof(string *)endl;//4

  cout sizeof(int *)endl;//4

  cout sizof(char * * * *)endl;//4

  可以看到,无论什么类型的指针,大小都是4,因为指针是32位物理地址。

  结论:只要是指针,大小都是4。(在64位机器上不一定是8)。

  顺便说一下,C中的指针表示实际内存的地址。与C不同,C取消了调式划分,即没有小、中、大,取而代之的是统一的平。平面模式采用32位实地址寻址,而不是C语言中的段:偏移模式.例如,如果有一个指向地址f000:8888的指针,如果是C类型,则为8888(16位,只存储位移,省略段),如果是C类型,则为f0008888(32位,高位保留段地址,位置保留位移),如果是C类型,则为f8888(32位,相当于段地址*16)。

  5.数组问题

  考虑以下问题:

  char a[]= abcdef ;

  int b[20]={3,4 };

  char c[2][3]={aa , bb };

  cout sizeof(a)endl;//7

  cout sizeof(b)endl;//20*4

  cout sizeof(c)endl;//6

  数组的大小在定义的时候是不指定的,编译时分配给它的空间是根据初始化的值,也就是7来确定的。c是多维数组,占用的空间是所有维度的乘积,也就是6。可以看出,数组的大小就是编译时分配的空间,也就是各个维度*数组元素大小的乘积。

  结论:数组的大小是维数*数组元素大小的乘积。

  这里有一个陷阱:

  int * d=new int[10];

  cout sizeof(d)endl;//4

  d就是我们常说的动态数组,但本质上是一个指针,所以sizeof(d)的值是4。

  考虑以下问题:

  double *(* a)[3][6];

  cout sizeof(a)endl;//4

  cout sizeof(* a)endl;//72

  cout sizeof(* * a)endl;//24

  cout sizeof(* * * a)endl;//4

  cout sizeof(* * * * a)endl;//8

  a是一个奇怪的定义。它意味着指向double*[3][6]类型数组的指针。既然是指针,sizeof(a)就是4。

  由于A是double*[3][6]的指针,*a表示double*[3][6]的多维数组类型,所以sizeof(* A)=3 * 6 * sizeof(double *)=72。同样,**a表示double*[6]类型的数组,所以sizeof(* * a)=6 * sizeof(double *)=24。***a表示元素之一,即double*,所以sizeof(***a)=4。至于****a是double,所以sizeof (* * * a)=sizeof (double)=8。

  6.将数组传递给函数的问题。

  考虑以下问题:

  #包括iostream

  使用命名空间std

  int Sum(int i[])

  {

  int sumo fi=0;

  for(int j=0;j sizeof(I)/sizeof(int);J) //实际上,sizeof(i)=4

  {

  sumo fi=I[j];

  }

  归还苏莫菲;

  }

  int main()

  {

  int allAges[6]={21,22,22,19,34,12 };

  cout Sum(all ages)endl;

  系统(“暂停”);

  返回0;

  }

  Sum的本意是用sizeof得到数组的大小,然后求和。但实际上传递给函数Sum的只是一个int指针,所以sizeof(i)=4,而不是24,所以会产生错误的结果。这个问题的解决方案是使用指针或引用。

  指针的使用:int Sum(int (*i)[6])

  {

  int sumo fi=0;

  for(int j=0;j sizeof(* I)/sizeof(int);j ) //sizeof(*i)=24

  {

  sumo fi=(* I)[j];

  }

  归还苏莫菲;

  }

  int main()

  {

  int allAges[]={21,22,22,19,34,12 };

  cout Sum(all ages)endl;

  系统(“暂停”);

  返回0;

  }

  在这个Sum中,I是指向I型的指针[6]。注意,这里不能用int Sum(int (*i)[])声明函数,但必须指明要传入的数组大小,否则sizeof(*i)无法计算。但是,在这种情况下,通过sizeof计算数组大小是没有意义的,因为大小被指定为6。

  引用的用法类似于指针:int Sum(int (i)[6])

  {

  int sumo fi=0;

  for(int j=0;j sizeof(I)/sizeof(int);j)

  {

  sumo fi=I[j];

  }

  归还苏莫菲;

  }

  int main()

  {

  int allAges[]={21,22,22,19,34,12 };

  cout Sum(all ages)endl;

  系统(“暂停”);

  返回0;

  }

  在这种情况下,size of的计算也是没有意义的,所以当数组作为参数,需要遍历时,函数要有一个参数来说明数组的sizeof,数组的大小在数组定义的范围内由sizeof来求值。因此,上述函数的正确形式应该是:#include iostream

  使用命名空间std

  int Sum(int *i,无符号int n)

  {

  int sumo fi=0;

  for(int j=0;j j)

  {

  sumo fi=I[j];

  }

  归还苏莫菲;

  }

  int main()

  {

  int allAges[]={21,22,22,19,34,12 };

  cout Sum(i,sizeof(all ages)/sizeof(int))endl;

  系统(“暂停”);

  返回0;

  }

  7.字符串的大小和长度

  考虑以下问题:char a[]= abcdef ;

  char b[20]= abcdef ;

  string s= abcdef

  cout strlen(a)endl;//6,字符串长度

  cout sizeof(a)endl;//7,字符串容量

  cout strlen(b)endl;//6,字符串长度

  cout strlen(b)endl;//20,字符串容量

  cout sizeof(s)endl;//12,这里不是字符串的长度,而是字符串类的大小。

  cout strlen(s)endl;//错误!s不是字符指针。

  a[1]=/0 ;

  cout strlen(a)endl;//1

  cout sizeof(a)endl;//7,sizeof是常数。

  Strlen将查找从指定地址到出现的第一个0的字符数。它在运行阶段执行,sizeof是获取的数据的大小,这里是获取的字符串的容量。所以对于同一个对象,sizeof的值是常数。是C类型的字符串,这是一个类,所以sizeof(s)表示的不是字符串的长度,而是类字符串的大小。Stren (s)根本就是错的,因为Stren的参数是一个字符指针。如果想用strren得到s字符串的长度,应该使用sizeof(s.c_str()),因为string的成员函数c_str()返回的是字符串的第一个地址。实际上string类提供了自己的成员函数来获取字符串的容量和长度,分别是Capacity()和Length()。String封装了常见的字符串操作,所以在C开发的过程中最好使用string而不是C类型的string。

  注意:关于sizeof(string),似乎不同的实现返回不同的结果:

  DevCPP:4

  VS2005:32

  8.从并集的大小问题看cpu的边界

  考虑以下问题:(默认对齐)union u

  {

  双a;

  int b;

  };

  联合u2

  {

  char a[13];

  int b;

  };

  联合u3

  {

  char a[13];

  char b;

  };

  cout sizeof(u)endl;//8

  cout sizeof(U2)endl;//16

  cout sizeof(u3)endl;//13

  众所周知,工会的规模取决于在其所有成员中占据最大空间的成员的规模。所以对于u,size是最大的double成员A,所以sizeof(u)=sizeof(double)=8。但是对于u2和u3,最大的空间是char类型的数组[13]。为什么u3的尺寸是13,u2的尺寸是16?关键在于u2中的成员int b。由于int类型成员的存在,u2的对齐方式变成了4,即u2的大小一定在4的对面边界上,所以占用的空间变成了16(13的最近对面边界)。

  结论:复合数据类型的对齐,如union、struct、class,是成员间对齐最大的成员的对齐。

  对了,CPU绑定问题,32位C使用8位绑定来提高运行速度,所以编译器会尽量把数据放到它的绑定上来提高内存命中率。边界可以改变。使用#pragma pack(x)宏可以改变编译器绑定的方式。默认值为8。固有类型C的界限采用编译器界限模式和自身大小中较小的一个。例如,如果指定编译器的界限为2,int类型的大小为4,则int的界限是2和4中较小的一个。在默认的边界模式下,几乎所有的数据类型都不会大于默认的边界模式long double除外),所以所有内在类型的边界模式都可以认为是类型本身的大小。更改上面的程序:#pragma pack(2)

  联合u2

  {

  char a[13];

  int b;

  };

  联合u3

  {

  char a[13];

  char b;

  };

  #杂注包(8)

  cout sizeof(U2)endl;//14

  cout sizeof(u3)endl;//13

  由于手动将绑定模式改为2,int的绑定也变成2,u2的绑定取成员的最大绑定,也是2,所以此时sizeof(u2)=14。

  结论:C内部类型的界限是编译器界限模式和自身大小中的较小者。

  9.结构尺寸问题

  因为对齐问题使得结构的sizeof更加复杂,所以看下面的例子:(默认对齐下)struct s1

  {

  char a;

  双b;

  int c;

  char d;

  };

  结构s2

  {

  char a;

  char b;

  int c;

  双d;

  };

  cout sizeof(S1)endl;//24

  cout sizeof(S2)endl;//16

  同样是两个char类型,一个int类型,一个double类型,但是因为边界问题,大小不一样。元素放置方法可用于计算结构的大小。我举个例子说明一下:首先,CPU判断结构的界限。根据上一节的结论,s1和s2的界限是最大的元素类型,也就是double类型8的界限。然后开始放置每个元素。

  对于s1,首先把A放在8的边界上,假设是0。此时,下一个空闲地址是1,但是下一个元素D是double类型。要放在8的边界上,离1最近的地址是8,所以D放在8上。此时下一个空闲地址变成16,下一个元素C的边界是4,可以满足,所以C放在16上。这时候,下一个免费地址。由于s1的大小需要是8的倍数,所以预留了21-23的空间,s1的大小就变成了24。

  对于s2,首先把A放在8的界内,假设是0,那么下一个空闲地址是1,下一个元素的界也是1,那么B放在1,下一个空闲地址就变成2;下一个元素C的对界是4,所以取最接近2的地址4放C,下一个空闲地址变成8,下一个元素D的对界是8,所以D放在8,所有元素都放,结构到15结束,总共占用16的空间,正好是8的倍数。

  这里有一个陷阱。对于一个结构体中的一个结构构件,不要认为它的对齐就是他的大小。看看下面的例子:结构s1

  {

  char a[8];

  };

  结构s2

  {

  双d;

  };

  结构s3

  {

  S1 s;

  char a;

  };

  结构s4

  {

  S2 s;

  char a;

  };

  cout sizeof(S1)endl;//8

  cout sizeof(S2)endl;//8

  cout sizeof(S3)endl;//9

  cout sizeof(S4)endl;//16;

  虽然s1和s2的大小都是8,但是s1的排列是1,s2是8(double),所以s3和s4有这样的区别。

  所以你自己定义结构的时候,如果空间紧张,最好考虑对齐因子来安排结构中的元素。

  10.不要让double干扰您的位域。

  在结构和类中,位字段可以用来指定一个成员占用的空间,所以使用位字段可以在一定程度上节省结构占用的空间。但是请考虑下面的代码:struct s1

  {

  int I:8;

  int j:4;

  双b;

  int a:3;

  };

  结构s2

  {

  int I;

  int j;

  双b;

  int a;

  };

  结构s3

  {

  int I;

  int j;

  int a;

  双b;

  };

  结构s4

  {

  int I:8;

  int j:4;

  int a:3;

  双b;

  };

  cout sizeof(S1)endl;//24

  cout sizeof(S2)endl;//24

  cout sizeof(S3)endl;//24

  cout sizeof(S4)endl;//16

  可以看到,double的存在会干扰bit字段(sizeof的算法参考上一节),所以在使用bit字段的时候,最好把float类型和double类型放在程序的开头或者结尾。

  C语言中判断数据类型的长度符号

  使用

  Sizeof(类型说明符、数组名或表达式);

  或者

  变量名的大小

  1.定义:

  Sizeof是C/C中的一个运算符,简单来说,它的作用是返回一个对象或类型占用的内存字节数。

  MSDN的解释是:

  sizeof关键字给出与变量或类型(包括聚合类型)相关联的存储量,以字节为单位。该关键字返回size_t类型的值。

  它的返回值类型是size_t,在头文件stddef.h中定义,这是一个依赖于编译系统的值,一般定义为

  typedef无符号int size _ t;

  世界上有很多编译器,但是作为一个规范,都是保证char,signed char,unsigned。

  char的sizeof值为1。毕竟,char是我们可以编程的最小数据类型。

  2.语法:

  Sizeof有三种语法形式,如下所示:

  1) sizeof(对象);//sizeof(object);

  2)sizeof(type _ name);//sizeof(类型);

  3) sizeof对象;//sizeof对象;

  所以,

  int I;

  sizeof(I);//好的

  sizeof I;//好的

  sizeof(int);//好的

  sizeof int//错误

  既然写3可以用写1代替,为了统一形式,减轻我们大脑的负担,那就忘了写3吧!实际上,sizeof sizeof计算对象的sizeof也被转换为对象类型的计算,也就是说,同一类型的不同对象的sizeof值是一致的。这里对象可以进一步扩展到表达式,即sizeof可以对一个表达式求值,编译器根据表达式的最终结果类型确定大小,一般不对表达式求值。比如:

  sizeof(2);//2的类型是int,所以等价于sizeof(int);

  sizeof(2 3.14);//3.14的类型是double,2也会提升为double类型,所以相当于sizeof(double);

  Zeof也可以评估函数调用。结果是函数返回类型的大小,该函数将不会被调用。让我们看一个完整的例子:

  char foo()

  {

  printf(foo()已被调用。/n’);

  返回“a”;

  }

  int main()

  {

  size _ t SZ=sizeof(foo());//foo()的返回值类型是char,所以sz=sizeof(char),foo()不会被调用。

  printf(sizeof( foo() )=%d/n ,SZ);

  }

  C99标准规定函数、待定类型的表达式、bit-field的成员不能计算为sizeof值,即以下写法都是错误的:

  sizeof(foo);//错误

  void foo2() { }

  sizeof(foo 2());//错误

  结构S

  {

  无符号整数f1:1;

  无符号整数F2:5;

  无符号int F3:12;

  };

  sizeof(s . f1);//错误

  3.Sizeof的恒定性

  sizeof的计算在编译时进行,因此它可以用作常量表达式,例如:

  char ary[sizeof(int)* 10];//好的

  最新的C99标准规定sizeof也可以在运行时计算。例如,下面的程序可以在Dev-C中正确执行:

  int n;

  n=10//n动态赋值

  char ary[n];//C99也支持数组的动态定义。

  printf(%d/n ,sizeof(ary));//好的。产出10

  但是在没有完全实现C99标准的编译器上就不行了,上面的代码也不能在VC6上编译。所以我们最好认为sizeof是在编译时执行的,不会带来错误,程序的可移植性更强。

  4.基本数据类型的大小

  这里的基本数据类型是指简单的内置数据类型,如short、int、long、float和double。由于它们都与系统相关,所以在不同的系统下它们的值可能不同。这必须引起我们的注意,尽量不要在这方面给自己程序的移植带来麻烦。

  一般32位编译环境下sizeof(int)的值是4。

  5.指针变量的大小

  如果你学过数据结构,应该知道指针是一个很重要的概念,它记录了另一个对象的地址。既然用来存储地址,当然等于计算机内部地址总线的宽度。因此,在32位计算机中,指针变量的返回值必须是4(注意结果是以字节为单位的)。可以预计,在未来的64位系统中,指针变量的sizeof结果将是8。

  char * pc= abc

  int * pi

  string * ps

  char** ppc=

  void(* pf)();//函数指针

  sizeof(PC);//结果是4

  sizeof(pi);//结果是4

  sizeof(PS);//结果是4

  sizeof(PPC);//结果是4

  sizeof(pf);//结果是4

  指针的sizeof值与指针指向的对象无关。正因为所有的指针变量占用相同的内存大小,MFC消息处理函数可以通过使用两个参数WPARAM和LPARAM来传递各种复杂的消息结构(使用指向结构的指针)。

  6.数组的大小

  数组的sizeof值等于数组占用的内存字节数,例如:

  char a1[]= ABC ;

  int a2[3];

  sizeof(a1);//结果是4,字符末尾也有一个空终止符

  sizeof(a2);//结果是3*4=12(取决于int)

  一开始有朋友认为sizeof就是求数组元素的个数。现在,你应该知道这是错误的,那么你应该如何找到数组元素的数目?简单,通常有两种写法:

  int C1=sizeof(a1)/sizeof(char);//总长度/单个元素的长度

  int C2=sizeof(a1)/sizeof(a1[0]);//总长度/第一个元素的长度

  写到这里,顺便问一下,下面的c3和c4值应该是什么?

  void foo3(char a3[3])

  {

  int C3=sizeof(a3);//c3==

  }

  void foo4(字符a4[])

  {

  int C4=sizeof(a4);//c4==

  }

  也许当你试图回答c4的值时,你才意识到c3是错的。是的,c3!=3。这里,函数参数a3不再是数组类型,而是指针,相当于char* a3。为什么仔细想想就不难理解了?当我们调用函数foo1时,程序会在堆栈上分配一个大小为3的数组吗?不要!数组是“寻址”的,调用者只需要传递参数的地址,所以a3自然是指针类型(char*),c3的值是4。

  7.结构的大小

  这是初学者最常问的问题,这里就要多花点笔墨了。我们先来看一个结构:

  结构S1

  {

  char c;

  int I;

  };

  问sizeof(s1)等于多少。你开始思考。char占1字节,int占4字节,所以加起来应该是5。真的吗?你在你的机器上试过吗?也许你是对的,但很可能你错了!根据VC6中的默认设置,结果为8。

  为什么我总是受伤?

  请不要沮丧。我们来思考一下sizeof的定义。——sizeof的结果等于对象或类型占用的内存字节数。好吧,我们来看看S1的内存分配:

  S1 s1={ a ,0x ffffffff };

  定义好以上变量后,添加断点,运行程序,观察s1所在的内存。你发现了什么?

  以我的VC6.0为例。s1的地址是0x0012FF78,其数据内容如下:

  0012FF78: 61 CC CC CC FF FF FF FF

  你发现了什么?为什么中间有一个3字节的CC?看看MSDN上的说明:

  当应用于结构类型或变量时,sizeof返回实际大小,其中可能包括为对齐而插入的填充字节。

  所以,这就是传说中的字节对齐!出现了一个重要的话题。

  为什么需要字节对齐?计算机组成原理告诉我们,这样有助于加快计算机的检索速度,否则需要更多的指令周期。为此编译器会默认处理结构(其实其他地方的数据变量也一样),这样宽度为2 (short等)的基本数据类型。)位于可被2整除的地址,宽度为4的基本数据类型(int等。)位于可被4整除的地址,依此类推。这样,可能需要在两个数之间添加填充字节,因此整个结构的sizeof值增加。

  让我们交换一下char和int在S1的位置:

  结构S2

  {

  int I;

  char c;

  };

  让我们看看sizeof(S2)的结果是什么。为什么还是8?那我们来看看内存。原来成员c后面还有3个填充字节,这是为什么?别担心。这里是规则的总结。

  字节对齐的细节与编译器实现有关,但一般来说,要满足三个标准:

  1)结构变量的第一个地址可以被它最宽的基本类型成员的大小整除;

  2)结构的每个成员相对于结构头地址的偏移量是成员大小的整数倍,必要时编译器会加上内部加法);成员之间的字节数;

  3)结构的总大小是结构的最宽基本类型成员大小的整数倍。如有必要,编译器将在最后一个成员后添加尾随填充。

  对于上述准则,有几点需要说明:

  1)我没说结构成员的地址是其大小的整数倍,但是怎么谈偏移量呢?因为第一点存在,所以我们只能考虑构件的偏移量,这个问题想起来很简单。想想为什么。

  结构成员相对于结构头地址的偏移量可以通过宏offsetof()获得,它也在stddef.h中定义如下:

  #定义offsetof(s,m) (size_t) (((s *)0)- m)

  例如,如果你想得到C在S2的偏移量,方法是

  size_t pos=offsetof(S2,c);//pos等于4

  2)基本类型是指前面提到的char、short、int、float、double等内置数据类型,这里的“数据宽度”是指其sizeof的大小。因为一个结构的成员可以是复合类型,比如另一个结构,所以在寻找最宽的基本类型成员时,我们应该包括复合类型成员的子成员,而不是把复合成员作为一个整体来对待。但是,在确定复合类型成员的偏移位置时,复合类型被视为一个整体。

  在这里描述有点拗口,想想也有点抓痒。举个例子(具体数值还是VC6,以后不解释):

  结构S3

  {

  char c1

  S1的;

  char c2

  };

  S1最宽简单成员的类型是int,S3在考虑最宽简单成员时“分散”了S1,所以S3最宽简单成员是int。这样,S3定义的变量的存储空间的第一个地址需要能被4整除,整个sizeof(S3)的值也要能被4整除。

  c1的偏移量为0,S的偏移量,此时S是一个整体。作为一个结构变量,它也满足前面的三个条件,所以它的大小是8,偏移量是4,所以c1和S之间需要三个填充字节,而c2和S之间不需要,所以c2的偏移量是12,把c2的大小算作13,13不能被4整除,所以最后要加三个填充字节。sizeof(S3)的最终值是16。

  通过以上描述,我们可以得到一个公式:

  结构的大小等于最后一个成员的偏移量加上其大小再加上末尾的填充字节数,即:

  sizeof( struct )=offsetof(最后一项)sizeof(最后一项)sizeof(尾部填充)

  至此,朋友们应该对sizeof结构有了全新的认识,但也不要高兴得太早。影响sizeof的一个重要参数还没有提到,那就是编译器的pack指令。它用于调整结构的对齐。不同的编译器在名称和用法上略有不同。在VC6中通过#pragma pack实现,也可以直接修改/Zp编译开关。#pragma pack的基本用法是:#pragma pack( n),其中n是字节对齐数。其值为1、2、4、8、16,默认值为8。如果该值小于结构成员的sizeof值,则

  成员的偏移量应该基于这个值,也就是说,结构成员的偏移量应该取两者的最小值。

  公式如下:

  offsetof( item )=min( n,sizeof( item))

  再看看这个例子:

  #pragma pack(push) //在堆栈上保存当前的包设置。

  #pragma pack(2) //必须在结构定义之前使用。

  结构S1

  {

  char c;

  int I;

  };

  结构S3

  {

  char c1

  S1的;

  char c2

  };

  #pragma pack(pop) //恢复以前的包设置

  计算sizeof(S1)时,min(2,sizeof(i))的值为2,所以I的偏移量为2,加上sizeof(i)等于6,可以被2整除,所以整个S1的大小为6。

  同样,对于sizeof(S3),s的偏移量是2,c2的偏移量是8,加上sizeof(c2)等于9,不能被2整除。添加一个填充字节,因此sizeof(S3)等于10。

  现在,朋友们可以轻松地呼吸了,)

  还需要注意的是,“空结构”(不包括数据成员)的大小不是0,而是1。想象一下一个“无空间”变量是如何被寻址的,以及两个不同的“空结构”变量是如何被区分的。因此,必须存储“空结构”变量,这样编译器只能分配一个字节的空间供其占用。如下所示:

  结构S5 { };

  sizeof(S5);//结果是1

  8.具有位域结构的sizeof

  如前所述,位字段的成员不能只接受sizeof值。这里要讨论的是包含位域的结构的sizeof,只是考虑到它的特殊性才列出来的。

  C99规定int、unsigned int和bool可以作为位域类型,但几乎所有编译器都对此进行了扩展,允许其他类型的存在。使用位域的主要目的是压缩存储,其一般规则如下:

  1)如果相邻位字段的类型相同,并且它们的位宽之和小于该类型的sizeof size,则下一个字段将紧挨着前一个字段存储,直到它不能被容纳为止;

  2)如果相邻的位字段是相同的类型,但是它们的位宽之和大于该类型的sizeof size,则随后的字段将从新的存储单元开始,并且它们的偏移量是它们的类型大小的整数倍;

  3)如果相邻位域的类型不同,每个编译器的具体实现也不同。VC6采用非压缩模式,Dev-C采用压缩模式;

  4)如果非比特字段字段散布在比特字段字段之间,则不执行压缩;

  5)整个结构的总大小是最宽基本类型的成员大小的整数倍。

  让我们看一个例子。

  示例1:

  结构BF1

  {

  char f1:3;

  char F2:4;

  char F3:5;

  };

  它的内存布局是:

   _ f1 _ _ _ _ F2 _ _ _ _ _ _ _ F3 _ _ _ _ _ _ _ _

  ________________

  0 3 7 8 1316

  字段类型为char,第1个字节只能存放f1和f2,所以f2被压缩到第1个字节,而f3只能

  可以从下一个字节开始。因此,sizeof(BF1)的结果是2。

  示例2:

  结构BF2

  {

  char f1:3;

  短F2:4;

  char F3:5;

  };

  由于相邻位域的类型不同,它的sizeof在VC6中是6,在DEV-C中是2。

  示例3:

  结构BF3

  {

  char f1:3;

  char f2

  char F3:5;

  };

  非位字段穿插其中,不会造成压缩。在VC6和Dev-C中获得的大小都是3。

  9.联合体的规模

  结构的记忆组织是顺序的,而联合体的记忆组织是重叠的。每个成员共享一个内存,所以整个联合体的sizeof就是每个成员的sizeof的最大值。结构的成员也可以是复合类型,其中复合类型成员被视为一个整体。

  因此,在以下示例中,u的sizeof值等于sizeof(s)。

  联合大学

  {

  int I;

  char c;

  S1的;

  };

  1.逗点算符

  逗号表达式是由逗号分隔的一组表达式,从左到右计算。逗号表达式的结果是其最右边表达式的值。如果最右边的操作数

  是左值,那么逗号表达式的值也是左值。这种表达式通常用于for循环:

  int CNT=ivec . size();

  for(vector int:size _ type IX=0;ix!=ivec . size();尺寸,- cnt)

  {

  ivec[IX]=CNT;

  }

  上面的for语句使循环表达式中的ix增加1,cnt减少1。ix和cnt的值应在每次循环中修改。当检查ix的条件判断成立时,程序将改变下一个元素

  重置为cnt的当前值。

  2.三元运算符(? )

  max=(a b)?甲:乙

  如果(a b)max=a;

  else max=b;

  x y?1:1.5将1转换为双精度类型

  3.功能

  (1)内置功能:

  调用一个函数需要一定的时间和空间。c提供了一种提高效率的方法,即在编译时将锁调用函数的代码直接嵌入到主函数中。这种嵌入

  主函数中的函数称为内置函数。

  注意:只有那些规模小、调用频繁的简单函数才适合声明为inine函数。

  (2)功能过载

  重载函数具有相同的函数名,但参数的数量、类型和顺序中至少有一个不同。

  (3)功能模板

  函数模板适用于函数体相同,函数的参数个数相同,但类型不同的情况。

  typename t//模板声明,其中t是类型参数。也可以使用模板类t。

  Max (t a,t b,t c)//定义一个通用函数,用t作为虚函数名。

  {

  如果(b a)a=b;

  如果(c a)a=c;

  返回a;

  }

  可以有多个参数,数量可以根据需要确定。

  例如,模板类T1,类型名T2

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

相关文章阅读

  • office2010激活密钥大全 怎么永久激活office2010
  • project2010产品密钥免费_project2010激活密钥永久激活码
  • c语言调用退出函数 c语言退出整个程序怎么写
  • c语言中怎么给函数初始化 c语言的初始化语句
  • c语言编写函数计算平均值 c语言求平均函数
  • chatgpt是什么?为什么这么火?
  • ChatGPT为什么注册不了?OpenAI ChatGPT的账号哪里可以注册?
  • OpenAI ChatGPT怎么注册账号?ChatGPT账号注册教程
  • chatgpt什么意思,什么是ChatGPT ?
  • CAD中怎么复制图形标注尺寸不变,CAD中怎么复制图形线性不变
  • cad中怎么创建并使用脚本文件,cad怎么运行脚本
  • cad中快速计算器的功能,cad怎么快速计算
  • cad中快速修改单位的方法有哪些,cad中快速修改单位的方法是
  • cad中心点画椭圆怎么做,cad轴测图怎么画椭圆
  • CAD中常用的快捷键,cad各种快捷键的用法
  • 留言与评论(共有 条评论)
       
    验证码: