熟悉c的人都知道,sizeof是一个关键字而不是一个宏或者库函数什么的,他的值是在编译时确定的,如果这个不了解,可以现看看这篇文章和这篇文章。 既然如此,让我们先看下面几个小例子:
sizeof(int);
sizeof(char);
sizeof(double);
sizeof(int);
sizeof(char);
sizeof(double);
上面三行sizeof的值是多少呢?这里我们假定在32位的x86系统下。我们会得到答案:4,1,8。这个没什么吧,大多数人都应该知道。那么,下面这个:
sizeof(int);
sizeof(long);
sizeof(int);
sizeof(long);
在32位x86下,这两个是多少呢?4,8?
实际上,答案是4,4。我们需要注意,long类型在32位系统下是32位的。那么,64位下结果又如何呢?8,8?其实答案是4,8。另一个需要注意的是,64位下的int是32位的。
上面只是热热身,现在,让我们看sizeof的下面几种情形:
1、sizeof一个结构体。
这个我就不说啥了,具体的参考这篇文章。至于空的结构体,下面会解释。
2、sizeof数组、指针等 先看下面两个例子:
char a[100];
char b[100]="helloworld!";
char c[]="helloworld!";
char* d=b;
sizeof(a);
sizeof(b);
sizeof(c);
sizeof(d);
char a[100];
char b[100]="helloworld!";
char c[]="helloworld!";
char* d=b;
sizeof(a);
sizeof(b);
sizeof(c);
sizeof(d);
在32位x86系统下,以上各是多少呢?
答案是:100,100,12,4。
为什么不是100,12,12,12呢? sizeof一个数组名,返回的是数组的大小,不管你数组里面放的什么数据。所以,第一个数组大小是100,第二个数组大小是100,第三个数组大小是12(别忘记"\0")。第四个呢?第四个不是一个数组名,而是一个指针!32位下指针大小永远是4,不管你是指向一个数组还是一个int还是一个char。 好,这个问题搞清楚之后,看下面这个程序:
int func(char a[100])
{
printf("%d\n", sizeof(a));
}
int main()
{
char *m = "helloworld!";
func(m);
char n[100]="helloworld!";
func(n);
}
int func(char a[100])
{
printf("%d\n", sizeof(a));
}
int main()
{
char *m = "helloworld!";
func(m);
char n[100]="helloworld!";
func(n);
}
这个程序会打印出什么结果呢?
答案是:4, 4。 为什么结果都是4?不是应该返回数组长度么?
这里出现又一个需要注意的地方:在作为参数传递的时候,数组名会退化为指针。也就是说,这里的func里的参数,虽然看上去是个数组名,但实际上还是个指针。 你了解了么?下面是几个练习,自己实验下^_^
char *p = NULL;
sizeof(p);
sizeof(*p);
int a[100];
sizeof(a);
sizeof(a[100]);
sizeof(&a);
sizeof(&a[0]);
char *p = NULL;
sizeof(p);
sizeof(*p);
int a[100];
sizeof(a);
sizeof(a[100]);
sizeof(&a);
sizeof(&a[0]);
懒得实验?答案分别是4,1,400,4,4,4。为什么?自己想想。
3、sizeof一些诡异的东西
(enum,空类,空struct) 所谓的诡异的东西,就是一些你想到的想不到的东西拿来sizeof。比如说sizeof一个enum类型是多少?一个空struct呢?一个空类呢? 这些诡异的东西在标准C中都没有作出规定,很大程度上都是编译器和系统结构相关的。 先来看一个:
int main()
{
enum week{Mon, Tue, Wed, Thu, Fri, Sat, Sun};
printf("%d\n", sizeof(enum week));
}
int main()
{
enum week{Mon, Tue, Wed, Thu, Fri, Sat, Sun};
printf("%d\n", sizeof(enum week));
}
这个你会得到什么样的结果呢?28? 在gcc或者vc下运行一把,你会得到答案:4。
为什么呢? 实际上,enum具体有多大取决于编译器的实现,目前大多数的编译器都将其实现为int类型。也就是说这里的enum被当作int类型(当然,使用上不一样)。这不是一成不变的,有些编译器,如VC++允许下面这种定义:
//注意这是个cpp文件
enum Color : unsigned char
{
red, green, blue
};
// assert(sizeof(Color) == 1);
//注意这是个cpp文件
enum Color : unsigned char
{
red, green, blue
};
// assert(sizeof(Color) == 1);
enum先说到这里,那么一个空的结构体是多大呢? 如果你擅长C语言,你可以很快的写出下面的程序:
//this is a *.c file
struct node{
}Node;
int main
{
printf("%d\n", sizeof(Node));
}
//this is a *.c file
struct node{
}Node;
int main
{
printf("%d\n", sizeof(Node));
}
很快,你可以验证出来结果是0。 没错,这很好理解。但是,如果你用的是c++呢?
//this is a *.cpp file
struct node{
}Node;
class node2{
}Node2;
int main()
{
printf("%d\n", sizeof(Node));
printf("%d\n", sizeof(Node2));
}
//this is a *.cpp file
struct node{
}Node;
class node2{
}Node2;
int main()
{
printf("%d\n", sizeof(Node));
printf("%d\n", sizeof(Node2));
}
(不怎么会写c++的我表示压力很大)以上这个c++的例子结果是多少呢?
为什么会得到1,1这个结果呢? 换句话说就是为什么sizeof一个空类和空结构体在c++下就是1呢?
这个原因要追朔到c++标准中的一句话:“no object shall have the same address in memory as any other variable”, 用中国话简单点说就是:不同的对象之间应该有不同的地址(为什么会有这样的规定?看这里)。
既然每个对象都必须有不同的地址,让我们假设上面代码中的Node的size是0,想想会出现什么样的后果?
Node a;
Node b;
Node a;
Node b;
a的大小是0,b的大小是0,那么,a和b的地址是不是很可能重复了?
所以,为了保证不同的对象拥有不同的地址,最简单的方法就是保证所有类型的大小都不是0。
所以,为了保证这点,大多数c++编译器都会给空结构或类加上一个冗余的字节保证类型不为空。
我的解释的清楚么?如果我的表达能力不够好,看这里,解释的足够详细。 当然,还有其他很多我没有想到的诡异的东西可以拿来sizeof,如果你想到了,欢迎跟我分享。至于c++中的sizeof类,基类,派生类,足够可以作为一个专门的文章了,先不再这里说,等我学会C++的再写一下相关内容(-_-")。
最后,给一个稍微给力点的程序,大家看看最终得到的结果是什么(注意这是一个c++程序):
//this is a cpp file
typedef struct weekday_st
{
enum week {sun=123456789,mon,tue,wed,thu,fri,sat,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak};
enum day{monring, moon, aftermoon};
}weekday_st;
int main(int argc, char *argv[])
{
printf( "sizeof(weekday_st)=%d\n ", sizeof(weekday_st));
printf( "sizeof(weekday)=%d\n ", sizeof(weekday_st::week));
printf( "sizeof(day)=%d\n ", sizeof(weekday_st::day));
return 0;
}
//this is a cpp file
typedef struct weekday_st
{
enum week {sun=123456789,mon,tue,wed,thu,fri,sat,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak};
enum day{monring, moon, aftermoon};
}weekday_st;
int main(int argc, char *argv[])
{
printf( "sizeof(weekday_st)=%d\n ", sizeof(weekday_st));
printf( "sizeof(weekday)=%d\n ", sizeof(weekday_st::week));
printf( "sizeof(day)=%d\n ", sizeof(weekday_st::day));
return 0;
}
anyShare分享到: