您的位置:首页 > 其它

Sizeof与Strlen的区别与联系

2012-04-24 19:59 246 查看


Sizeof与Strlen的学习

【几个例子】

例子1:
char* ss = "0123456789";
sizeof(ss) //4, ss是指向字符串常量的字符指针
strlen(ss) //10, 只能用它获得这个字符串的长度
char ss[] = "0123456789";
sizeof(ss) //11, ss是数组,计算到‘\0’位置,因此是10+1
strlen(ss) //10, strlen是个函数内部实现是用一个循环计算到\0为止之前
char ss[100] = "0123456789";
sizeof(ss) //100, ss表示在内存中的大小100×1
strlen(ss) //10, strlen是个函数内部实现是用一个循环计算到\0为止之前
int ss[100] = "0123456789";
sizeof(ss) //400, ss表示再内存中的大小100×4
strlen(ss) //错误, strlen的参数只能是char*
且必须是以‘\0‘结尾
例子2:
class X
{
int i;
int j;
char k;
};
X x;
cout<<sizeof(X)<<endl; 结果 12
内存补齐
cout<<sizeof(x)<<endl; 结果 12
同上
例子3:
char szPath[MAX_PATH]
如果在函数内这样定义,那么sizeof(szPath)将会是MAX_PATH,但是将szPath作为虚参声明时(void
fun(char szPath[MAX_PATH])),sizeof(szPath)却会是4(指针大小),即如果操作数是函数中的数组形参或函数类型的形参,sizeof给出其指针的大小。
【sizeof与strlen区别总结】
1.sizeof是运算符,strlen是函数。
2. strlen是有效字符串的长度,不包含‘\0’,与初始化有关系,而sizeof与初不初始化没有关系
3.sizeof可以用类型做参数,用来计算类型占内存大小,strlen只能用char*做参数,且必须是以'\0'结尾的,用来计算字符串的长度;
4.数组做sizeof的参数不退化,传递给strlen就退化为指针了。
5. sizeof在编译时计算,而strlen的结果在运行时才能计算出来,
【课堂测试】
1. 如下程序的输出是什么?(在intel x86(32-bit) platform.)
#include <stdio.h>

#include<stdlib.h>

#include<string.h>

int main( )

{

char str[10];

char *p;

memset(str,0x00,sizeof(str));

p = (char *)malloc(100);

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

printf("%d\n",sizeof('p'));

printf("%d\n",strlen(str));

exit(0);

}
答:4/1/0,
如果不加memset(),第三行就会打出15(随机数),请问这是为什么?memset函数是初始化分配的内存空间,使用0、0x00都是0即’\0',不同系统当分配一块内存时,这块内存中的内容是未知的,系统只是根据申请者的要求为其化一块内存并不管他原先的内容是什么(有的系统清零),所以你的是随即数15。
2.你能够正确的说出它们的sizeof和strlen的大小吗?
#include <stdio.h>

#include<stdlib.h>

#include<string.h>

int main( )

{

char *str1="absde";

char str2[]="absde";

char str3[8]={'a',};

char str4[8]={'a','b','s','e','f','g','h','j'};
printf("sizeof(str1)=%d\n",sizeof(str1));

printf("sizeof(str2)=%d\n",sizeof(str2));

printf("sizeof(str3)=%d\n",sizeof(str3));

printf("sizeof(str4)=%d\n",sizeof(str4));
printf("strlen(str1)=%d\n",strlen(str1));

printf("strlen(str2)=%d\n",strlen(str2));

printf("strlen(str3)=%d\n",strlen(str3));

printf("strlen(str4)=%d\n",strlen(str4));
exit(0);

}

答:sizeof是计算括号中变量的类型所占的储存空间(不考虑内容);strlen是计算变量值为起点的内存地址到第一个'\0'的距离,以字节为单位,字符串尾部为'\0',0=='\0'(不包括’\0’)。正确答案是:4、6、8、8;5、5、1、9;
3. 你能够正确的说出它们的sizeof和strlen的大小吗?
char *str1="absde";

char str2[]="absde";

char str3[8]={'a',};

char str4[8]={'a','b','s','e','f','g','h','j'};
答案:
sizeof(str1)=4;

sizeof(*str1)=1;

strlen(str1)=5;

sizeof(str2)=6;

strlen(str2)=5;

sizeof(str3)=8;

strlen(str3)=1;

sizeof(str4)=8;

strlen(str4)=13;

strlen(*str1) 出错
strlen(str4)有可能为不小于8的其他数字,取决于内存中的数据,因为strlen是计算变量值为起点的内存地址到第一个'\0'的距离,但'\0'出现位置我们是未知的。
6月12日 17:49 | 添加评论 | 固定链接 | 写入日志 | C/C++
关于Sizeof
一、sizeof的概念
sizeof是C语言的一种单目操作符,如C语言的++、--等。它并不是函数。sizeof操作符以字节形式给出了其操作数的存储大小。操作数可以是一个表达式或括在括号内的类型名。操作数的存储大小由操作数的类型决定。其实可以简单的理解sizeof是征对"类型"的。
二、sizeof的使用方法
1、用于数据类型 
sizeof使用形式:sizeof(type),数据类型必须用括号括住。如sizeof(int)。
2、用于变量
sizeof使用形式:sizeof(var_name)或sizeof
var_name
变量名可以不用括号。如sizeof (var_name),sizeof var_name等都可以。带括号的用法更普遍,大多数程序员采用这种形式。 
注意:sizeof操作符不能用于函数类型,不完全类型或位字段。不完全类型指具有未知存储大小的数据类型,如未知存储大小的数组类型、未知内容的结构或联合类型、void类型等。 
三、sizeof的结果
sizeof操作符的结果类型是size_t,它在头文件中typedef为unsigned
int类型。该类型保证能容纳实现所建立的最大对象的字节大小。
1、若操作数具有类型char、unsigned char或signed
char,其结果等于1。因为ANSI C正式规定字符类型为1字节。
2、int、unsigned int 、short
int(short)、unsigned short 、long int(long) 、unsigned
long 、float、double、long double类型的sizeof 在ANSI
C中没有具体规定,大小依赖于实现,一般可能分别为2、2、2、2、4、4、4、8、10。
3、当操作数是指针时,sizeof依赖于编译器。例如Microsoft C/C++7.0中,near类指针字节数为2,far、huge类指针字节数为4。一般Unix的指针字节数为4。
4、当操作数具有数组类型时,其结果是数组的总字节数,特别要注意字符串数组,如:

Char str[]=“123456” sizeof(str)=7。
5、联合类型操作数的sizeof是其最大字节成员的字节数。结构类型操作数的sizeof是这种类型对象的总字节数,包括任何垫补在内。

让我们看如下结构: 

struct {char b; double x;} a;

在某些机器上sizeof(a)=16,而一般sizeof(char)+
sizeof(double)=9。

这是因为编译器在考虑对齐问题时,在结构中插入空位以控制各成员对象的地址对齐。
6、如果操作数是函数中的数组形参或函数类型的形参,sizeof给出其指针的大小。

即:int func(char p[100])

{ sizeof(p) = 4; }

C/C++中不能传数组,只能传指针,所以任何数组都会隐式转成指针形式进行操作,所以"类型"还是指针。
7.sizeof是运算符当编译器编译时会自动运算这个变量的大小的并使用它的大小代替sizeof的值如

int len = sizeof(int);编译时编译器计算出int的大小大小为4
所以把上面这句变成

int len = 4
四、sizeof与其他操作符的关系
sizeof的优先级为2级,比/、%等3级运算符优先级高。可与其他操作符一起组成表达式。如i*sizeof(int);其中i为int类型变量。
五、sizeof的主要用途
1、sizeof操作符的一个主要用途是与存储分配和I/O系统那样的例程进行通信。例如: 

void *malloc(size_t size),

size_t fread(void * ptr,size_t size,size_t nmemb,FILE * stream)。 
2、sizeof的另一个的主要用途是计算数组中元素的个数。例如: 

void *memset(void *s,int c,sizeof(s))。
3.在动态分配一对象时,可以让系统知道要分配多少内存。
如:int *p=(int *)malloc(sizeof(int)*10);
4.由于操作数的字节数在实现时可能出现变化,建议在涉及到操作数字节大小时用sizeof来代替常量计算。
5.如果操作数是函数中的数组形参或函数类型的形参,sizeof给出其指针的大小。
六、建议
由于操作数的字节数在实现时可能出现变化,建议在涉及到操作数字节大小时用ziseof来代替常量计算。

函数简介

  原型:extern unsigned int strlen(char *s);,在Visual C++ 6.0中,原型为size_t
strlen( const char *string );,其中size_t实际上是unsigned int,在VC6.0中可以看到这样的代码:typedef
unsigned int size_t;。
  头文件:string.h

  功能:计算字符串s的(unsigned int型)长度
  说明:返回s的长度,不包括结束符NULL。
  相关函数:
  
TCHAR.H routine

_UNICODE & _MBCS not defined

_MBCS defined

_UNICODE defined

_tcslen

strlen

strlen

wcslen

_tcsclen

strlen

_mbslen

wcslen

程序举例

  举例1:(在Visual C++6.0中运行通过)
  #include <string.h>

  #include<STDIO.H>

  int main(void)

  {

  char *s="Golden Global View";

  printf("%s has %d chars",s,strlen(s));

  getchar();

  return 0;

  }

与sizeof()的区别

  strlen(char*)函数求的是字符串的实际长度,它求得方法是从开始到遇到第一个'\0',如果你只定义没有给它赋初值,这个结果是不定的,它会从aa首地址一直找下去,直到遇到'\0'停止。
  char aa[10];cout<<strlen(aa)<<endl; //结果是不定的
  char aa[10]={'\0'}; cout<<strlen(aa)<<endl; //结果为0

  char aa[10]="jun"; cout<<strlen(aa)<<endl; //结果为3

  而sizeof()返回的是变量声明后所占的内存数,不是实际长度,此外sizeof不是函数,仅仅是一个操作符,strlen是函数。
  sizeof(aa)
返回10
  int a[10]; sizeof(a)
返回40
  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); //a=10;

  int b=sizeof(str); //而b=20;

  6.strlen的结果要在运行的时候才能计算出来,时用来计算字符串的长度,不是类型占内存的大小。
  7.sizeof后如果是类型必须加括弧,如果是变量名可以不加括弧。这是因为sizeof是个操作符不是个函数。
  8.当适用了于一个结构类型时或变量, sizeof
返回实际的大小,
  当适用一静态地空间数组, sizeof
归还全部数组的尺寸。
  sizeof
操作符不能返回动态地被分派了的数组或外部的数组的尺寸
  9.数组作为参数传给函数时传的是指针而不是数组,传递的是数组的首地址,
  如:
  fun(char [8])

  fun(char [])

  都等价于 fun(char *)

  在C++里参数传递数组永远都是传递指向数组首元素的指针,编译器不知道数组的大小
  如果想在函数内知道数组的大小,需要这样做:

  进入函数后用memcpy拷贝出来,长度由另一个形参传进去
  fun(unsiged char *p1, int len)

  {

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

  memcpy(buf, p1, len);

  }

  我们能常在用到 sizeof
和 strlen 的时候,通常是计算字符串数组的长度
  看了上面的详细解释,发现两者的使用还是有区别的,从这个例子可以看得很清楚:
  char str[20]="0123456789";

  int a=strlen(str); //a=10; >>>> strlen
计算字符串的长度,以结束符 0x00 为字符串结束。
  int b=sizeof(str); //而b=20; >>>> sizeof
计算的则是分配的数组 str[20] 所占的内存空间的大小,不受里面存储的内容改变。
  上面是对静态数组处理的结果,如果是对指针,结果就不一样了
  char* ss = "0123456789";

  sizeof(ss)
结果 4 ===》ss是指向字符串常量的字符指针,sizeof
获得的是一个指针的之所占的空间,应该是
  长整型的,所以是4

  sizeof(*ss)
结果 1 ===》*ss是第一个字符其实就是获得了字符串的第一位'0'
所占的内存空间,是char类
  型的,占了 1

  strlen(ss)= 10 >>>>
如果要获得这个字符串的长度,则一定要使用 strlen

  sizeof返回对象所占用的字节大小. //正确
  strlen返回字符个数. //正确
  在使用sizeof时,有一个很特别的情况,就是数组名到指针蜕变,
  char Array[3] = {'0'};

  sizeof(Array) == 3;

  char *p = Array;

  sizeof(p) == 1;//sizeof(p)结果为4

  在传递一个数组名到一个函数中时,它会完全退化为一个指针
  ----------------------------------------------------------

  看完以上你是否很清楚sizeof和strlen的区别了呢?还不明白的话,我们看下面几个例子:
  第一个例子
  char* ss = "0123456789";

  sizeof(ss)
结果 4 ===》ss是指向字符串常量的字符指针
  sizeof(*ss)
结果 1 ===》*ss是第一个字符
  大部分编译程序在编译的时候就把sizeof计算过了是类型或是变量的长度
  这就是sizeof(x)可以用来定义数组维数的原因
  char str[20]="0123456789";

  int a=strlen(str); //a=10;

  int b=sizeof(str); //而b=20;

  大部分编译程序在编译的时候就把sizeof计算过了是类型或是变量的长度
  这就是sizeof(x)可以用来定义数组维数的原因
  char str[20]="0123456789";

  int a=strlen(str); //a=10;

  int b=sizeof(str); //而b=20;

  char ss[] = "0123456789";

  sizeof(ss)
结果 11 ===》ss是数组,计算到\0位置,因此是10+1

  sizeof(*ss)
结果 1 ===》*ss是第一个字符
  char ss[100] = "0123456789";

  sizeof(ss)
结果是100 ===》ss表示在内存中的大小 100×1

  strlen(ss)
结果是10 ===》strlen是个函数内部实现是用一个循环计算到\0为止之前
  int ss[100] = "0123456789";

  sizeof(ss)
结果 400 ===》ss表示再内存中的大小 100×4

  strlen(ss)
错误===》strlen的参数只能是char*
且必须是以'\0'结尾的
  char q[]="abc";

  char p[]="a\n";

  sizeof(q),sizeof(p),strlen(q),strlen(p);

  结果是 4 3 3 2

  第二个例子
  class X

  {

  int i;

  int j;

  char k;

  };

  X x;

  cout<<sizeof(X)<<endl;
结果 12 ===》内存补齐
  cout<<sizeof(x)<<endl;
结果 12 同上
  第三个例第一个例子
  char* ss = "0123456789";

  sizeof(ss)
结果 4 ===》ss是指向字符串常量的字符指针
  sizeof(*ss)
结果 1 ===》*ss是第一个字符
  char ss[] = "0123456789";

  sizeof(ss)
结果 11 ===》ss是数组,计算到\0位置,因此是10+1

  sizeof(*ss)
结果 1 ===》*ss是第一个字符
  char ss[100] = "0123456789";

  sizeof(ss)
结果是100 ===》ss表示在内存中的大小 100×1

  strlen(ss)
结果是10 ===》strlen是个函数内部实现是用一个循环计算到\0为止之前
  int ss[100] = "0123456789";

  sizeof(ss)
结果 400 ===》ss表示再内存中的大小 100×4

  strlen(ss)
错误===》strlen的参数只能是char*
且必须是以'\0'结尾的
  char q[]="abc";

  char p[]="a\n";

  sizeof(q),sizeof(p),strlen(q),strlen(p);

  结果是 4 3 3 2

  第二个例子
  class X

  {

  int i;

  int j;

  char k;

  };

  X x;

  cout<<sizeof(X)<<endl;
结果 12 ===》内存补齐
  cout<<sizeof(x)<<endl;
结果 12 同上
  第三个例子

  char szPath[MAX_PATH]

  如果在函数内这样定义,那么sizeof(szPath)将会是MAX_PATH,但是将szPath作为虚参声明时(void
fun(char szPath[MAX_PATH])),sizeof(szPath)却会是4(指针大小)

  子
  char szPath[MAX_PATH]

  如果在函数内这样定义,那么sizeof(szPath)将会是MAX_PATH,但是将szPath作为虚参声明时(void
fun(char szPath[MAX_PATH])),sizeof(szPath)却会是4(指针大小)

  还有一位网友的说明也很好:
  其实理解 sizeof
只需要抓住一个要点:栈
  程序存储分布有三个区域:栈、静态和动态。能够从代码直接操作的对象,包括任何类型的变量、指针,都是在栈上的;动态和静态存储区是靠栈上的指所有针间接操作的。 sizeof
操作符,计算的是对象在栈上的投影体积;记住这个就很多东西都很清楚了。
  char const * static_string = "Hello";

  sizeof(static_string)
是 sizeof 一个指针,所以在 32bit system
是 4
  char stack_string[] = "Hello";

  sizeof(stack_string)
是 sizeof 一个数组,所以是 6 * sizeof(char)

  char * string = new char[6];

  strncpy(string, "Hello", 6");

  sizeof(string)
是 sizeof 一个指针,所以还是 4。和第一个不同的是,这个指针指向了动态存储区而不是静态存储区。
  不管指针指向的内容在什么地方,sizeof
得到的都是指针的栈大小
  C++
中对引用的处理比较特殊;sizeof 一个引用得到的结果是 sizeof
一个被引用的对象的大小;所以
  struct O

  {

  int a, b, c, d, e, f, g, h;

  };

  int main()

  {

  O & r = *new O;

  cout << sizeof(O) << endl; // 32

  cout << sizeof r << endl; //
也是 32
  system("PAUSE");

  }

r
引用的是整个的 O 对象而不是指向 O
的指针,所以 sizeof r 的结果和 sizeof O
完全相同。
自定义函数实现strlen()函数的功能
  下面几种实现strlen函数的源代码大家参考
  -------------------------------------------------1:start------------------------------------

  #include <stdio.h>

  #include <assert.h>

  typedef unsigned int u_int;

  u_int Mystrlen(const char *str)

  {

  u_int i;

  assert(str != NULL);

  for (i = 0; str[i]!= '\0'; i++);

  return i;

  }

  ------------------------------------------------1:end--------------------------------------

  -------------------------------------------------2:start--------------------------------------

  int strlen(const char *str)

  {

  assert(str != NULL);

  int len = 0;

  while((*str++) != '\0')

  len++;

  return len;

  }

  ------------------------------------------------2:end ------------------------------------------

  ------------------------------------------------3:start------------------------------------------

  int strlen(const char *str)

  {

  assert(str);

  const char *p = str;

  while(*p++!=NULL);

  return p - str - 1;

  }

  -------------------------------------------------3:end-----------------------------------------

  -------------------------------------------------4:start----------------------------------------

  int strlen(const char *str)

  {

  assert(str);

  if (*str==NULL)

  return 0;

  else

  return (1 + strlen(++str));

  }

  -----------------------------------------------4:end----------------------------------------

  以上各种实现的方式都是大同小异的,有的用的是变量,有的用的是指针。
  其中,最后一个用的是递归的方式。其实,在实现库函数的时候,是规定不可以
调用其他的库函数的,这里只是给大家一个方法,不用变量就可以实现strlen。
php语言函数strlen()
  strlen()
函数用于计算字符串的长度。
  让我们算出字符串 "Hello world!"
的长度:
  <?php

  echo strlen("Hello world!");

  ?>

  以上代码的输出:
  12字符串的长度信息常常用在循环或其他函数中,因为那时确定字符串何时结束是很重要的(例如,在循环中,我们需要在字符串中的最后一个字符之后结束循环)。

sizeof()

  sizeof是运算符,可用于任何变量名、类型名或常量值,当用于变量名(不是数组名)或常量时,它不需要用圆括号。

  它在编译时起作用,而不是运行时。

  这是初学者问得最多的一个问题,所以这里有必要多费点笔墨。让我们先看一个结构体:

  struct S1

  {

  char c;

  int i;

  };

  问sizeof(s1)等于多少聪明的你开始思考了,char占1个字节,int占4个字节,那么加起来就应该是5。是这样吗你在你机器上试过了吗也许你是对的,但很可能你是错的!VC6中按默认设置得到的结果为8。

  Why为什么受伤的总是我

  请不要沮丧,我们来好好琢磨一下sizeof的定义——sizeof的结果等于对象或者类型所占的内存字节数,好吧,那就让我们来看看S1的内存分配情况:

  S1 s1 = { 'a', 0xFFFFFFFF };

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

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

  0012FF78: 61 CC CC CC FF FF FF FF

  发现了什么怎么中间夹杂了3个字节的CC看看MSDN上的说明:

  When applied to a structure type or variable, sizeof returns the actual size, which may include padding bytes inserted for alignment.

  原来如此,这就是传说中的字节对齐啊!一个重要的话题出现了。

  为什么需要字节对齐计算机组成原理教导我们这样有助于加快计算机的取数速度,否则就得多花指令周期了。为此,编译器默认会对结构体进行处理(实际上其它地方的数据变量也是如此),让宽度为2的基本数据类型(short等)都位于能被2整除的地址上,让宽度为4的基本数据类型(int等)都位于能被
4整除的地址上,以此类推。这样,两个数中间就可能需要加入填充字节,所以整个结构体的sizeof值就增长了。

  让我们交换一下S1中char与int的位置:

  struct S2

  {

  int i;

  char c;

  };

  看看sizeof(S2)的结果为多少,怎么还是8再看看内存,原来成员c后面仍然有3个填充字节,这又是为什么啊别着急,下面总结规律。

  字节对齐的细节和编译器实现相关,但一般而言,满足三个准则:

  1)
结构体变量的首地址能够被其最宽基本类型成员的大小所整除;

  2)
结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding);

  3)
结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)。

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

  1)
前面不是说结构体成员的地址是其大小的整数倍,怎么又说到偏移量了呢因为有了第1点存在,所以我们就可以只考虑成员的偏移量,这样思考起来简单。想想为什么。

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

  #define offsetof(s,m) (size_t)&(((s *)0)->m)

  例如,想要获得S2中c的偏移量,方法为

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

  2)
基本类型是指前面提到的像char、short、int、float、double这样的内置数据类型,这里所说的“数据宽度”就是指其sizeof的大小。由于结构体的成员可以是复合类型,比如另外一个结构体,所以在寻找最宽基本类型成员时,应当包括复合类型成员的子成员,而不是把复合成员看成是一个整体。但在确定复合类型成员的偏移位置时则是将复合类型作为整体看待。

  这里叙述起来有点拗口,思考起来也有点挠头,还是让我们看看例子吧(具体数值仍以VC6为例,以后不再说明):

  struct S3

  {

  char c1;

  S1 s;

  char c2;

  };

  S1的最宽简单成员的类型为int,S3在考虑最宽简单类型成员时是将S1“打散”看的,所以S3的最宽简单类型为int,这样,通过S3定义的变量,其存储空间首地址需要被4整除,整个sizeof(S3)的值也应该被4整除。

  c1的偏移量为0,s的偏移量呢这时s是一个整体,它作为结构体变量也满足前面三个准则,所以其大小为8,偏移量为4,c1与s之间便需要3个填充字节,而c2与s之间就不需要了,所以c2的偏移量为12,算上c2的大小为13,13是不能被4整除的,这样末尾还得补上3个填充字节。最后得到
sizeof(S3)的值为16。

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

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

  sizeof( struct ) = offsetof( last item ) + sizeof( last item ) + sizeof( trailing padding )

  到这里,朋友们应该对结构体的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) //
将当前pack设置压栈保存

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

  struct S1

  {

  char c;

  int i;

  };

  struct S3

  {

  char c1;

  S1 s;

  char c2;

  };

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

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

  同样,对于sizeof(S3),s的偏移量为2,c2的偏移量为8,再加上sizeof(c2)=1结果为9,不能被2整除,添加一个填充字节,所以sizeof(S3)等于10。

  现在,朋友们可以轻松的出一口气了,:)

  还有一点要注意,“空结构体”(不含数据成员)的大小不为0,而是1。试想一个“不占空间”的变量如何被取地址、两个不同的“空结构体”变量又如何得以区分呢于是,“空结构体”变量也得被存储,这样编译器也就只能为其分配一个字节的空间用于占位了。如下:

  struct S5 { };

  sizeof( S5 ); //
结果为1

  第一个例子: char* ss = "0123456789";

  sizeof(ss)
结果 4 ===》ss是指向字符串常量的字符指针

  sizeof(*ss)
结果 1 ===》*ss是第一个字符

  char ss[] = "0123456789";

  sizeof(ss)
结果 11 ===》ss是数组,计算到\0位置,因此是10+1

  sizeof(*ss)
结果 1 ===》*ss是第一个字符

  char ss[100] = "0123456789";

  sizeof(ss)
结果是100 ===》ss表示在内存中的大小 100×1

  int ss[100] = "0123456789";

  sizeof(ss)
结果 400 ===》ss表示再内存中的大小 100×4

  char q[]="abc";

  char p[]="a\n";

  sizeof(q),sizeof(p),strlen(q),strlen(p);

  结果是 4 3 3 2

  第二个例子:class X

  {

  int i;

  int j;

  char k;

  };

  X x;

  cout<<sizeof(X)<<endl;
结果 12 ===》内存补齐

  cout<<sizeof(x)<<endl;
结果 12 同上

  ----------------

  sizeof()和strlen()区别:

  #include <iostream.h>

  #include <string>

  void main()

  {

  char cha[10]={'a','b','c','d'};

  cout<<"chasz:"<<cha<<endl;

  cout<<"strlen:"<<strlen(cha)<<endl;

  cha[2]='\0';

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

  cout<<"strlen2:"<<strlen(cha)<<endl;

  }

  运行结果:

  chasz:abcd

  strlen:4

  sizeof:10

  strlen2:2

  Press any key to continue
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: