c关键字-sizeof的种种
熟悉c的人都知道,sizeof是一个关键字而不是一个宏或者库函数什么的,他的值是在编译时确定的,如果这个不了解,可以现看看这篇文章和这篇文章。 既然如此,让我们先看下面几个小例子:
sizeof(int); sizeof(char); sizeof(double); |
上面三行sizeof的值是多少呢?这里我们假定在32位的x86系统下。我们会得到答案:4,1,8。这个没什么吧,大多数人都应该知道。那么,下面这个:
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); |
在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); } |
这个程序会打印出什么结果呢?
答案是:4, 4。 为什么结果都是4?不是应该返回数组长度么?
这里出现又一个需要注意的地方:在作为参数传递的时候,数组名会退化为指针。也就是说,这里的func里的参数,虽然看上去是个数组名,但实际上还是个指针。 你了解了么?下面是几个练习,自己实验下^_^
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)); } |
这个你会得到什么样的结果呢?28? 在gcc或者vc下运行一把,你会得到答案:4。
为什么呢? 实际上,enum具体有多大取决于编译器的实现,目前大多数的编译器都将其实现为int类型。也就是说这里的enum被当作int类型(当然,使用上不一样)。这不是一成不变的,有些编译器,如VC++允许下面这种定义:
//注意这是个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)); } |
很快,你可以验证出来结果是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)); } |
(不怎么会写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; |
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, |
参考书目:《C专家编程》 《C语言深度解剖:解开程序员面试笔试的秘密 》
建议继续学习:
扫一扫订阅我的微信号:IT技术博客大学习
- 作者:sponge 来源: SpongeLiu的blog
- 标签: sizeof
- 发布时间:2012-09-18 23:57:04
- [54] IOS安全–浅谈关于IOS加固的几种方法
- [52] android 开发入门
- [52] 如何拿下简短的域名
- [51] 图书馆的世界纪录
- [49] Oracle MTS模式下 进程地址与会话信
- [49] Go Reflect 性能
- [47] 【社会化设计】自我(self)部分――欢迎区
- [46] 读书笔记-壹百度:百度十年千倍的29条法则
- [37] 程序员技术练级攻略
- [29] 视觉调整-设计师 vs. 逻辑