一、文章来由—一道面试题迁出的探究

我发现我已经形成一种习惯写来由了,以后看博客的时候能够让我回顾起为什么出现这个问题,我用什么方法解决的,既然形成习惯就让这个习惯保持下去吧。今天实验室师姐在看书,一处不解。是关于sizeof的,大家讨论此问题后,我一向信服做了才知道答案,于是有了这篇文章。

可是仅仅能叫小览,由于不可能总结完sizeof的使用方法,欢迎补充和讨论。

二、从这道题目说起

我直接将问题的关键部分提出来:

string strArr1[] = { "Trend", "Micro", "Soft" };
cout << "sizeof(strArr1) == " << sizeof(strArr1) << endl;

请问输出多少。书上的答案这样写道:

而字符串strArr1是由3段构成的,所 以sizeof(strArr1)大小是12。

首先要明白sizeof不是函数,也不是一元运算符,它是个相似宏定义的特殊关键字,特别是sizeof(string)=4

这个不去试是不知道的。由于编译器那么多。编译器做什么事情不去试怎么可能知道

果然,在vs2013 release Win32模式(x64模式还要更大)下结果是

sizeof(string) == 24

sizeof(strArr1) == 72

debug模式

sizeof(string) == 28

sizeof(strArr1) == 84

也是3倍关系,由于这是一个string数组。里面有三个string对象

那么为什么string有不同的结果?

查阅了相关资料得出结论:我们知道char*肯定是4字节,string里面可能不止包括一个char*那么简单,还包括有长度信息等其它信息。string的实如今各库中可能有所不同,可是在同一库中同样一点是,不管你的string里放多长的字符串,它的sizeof()都是固定的。字符串所占的空间是从堆中动态分配的,与sizeof()无关。

  sizeof(string)=4可能是最典型的实现之中的一个,只是也有sizeof()为12、32字节的库实现。 可是VC6.0測试后sizeof(string)=16.还是跟编译器有关

为了全然測试一些东西。我測试越写越多,然后我来了威力加强版。见代码:

#include<iostream>

using namespace std;

int main()
{
char p[] = { 'a', 'b', 'c', 'a', 'b', 'c' };
char *p1 = "abcabc";
char p2[] = "abcabc";
char p3[][2] = { { 'a', 'b' }, { 'c', 'a' }, { 'b', 'c' } };
printf("p == %s\n", p);
cout << p << endl;
cout << "sizeof(p) == " << sizeof(p) << endl;
cout << "sizeof(p1) == " << sizeof(p1) << endl;
cout << "sizeof(p2) == " << sizeof(p2) << endl;
cout << "sizeof(p3) == " << sizeof(p3) << endl; cout<<"sizeof(string) == " << sizeof(string) << endl; string strArr1[] = { "Trend", "Micro", "Soft" };
cout << "sizeof(strArr1) == " << sizeof(strArr1) << endl; int a = 0;
cout <<"sizeof(a = 3) == " << sizeof(a = 3) << endl;
cout << "a == " << a << endl; cout << "sizeof(999999) == " << sizeof(999999) << endl;
cout << "sizeof(9999999999999999999) == " << sizeof(9999999999999999999) << endl;
cout << "sizeof(9 / 5) == " << sizeof(9 / 5) << endl;
cout << "sizeof((double)9 / 5) == " << sizeof((double)9 / 5) << endl; return 0;
}

执行结果如图所看到的:

我来一一解释我的这些測试在做什么:

(1)首先p的这种初始化方式。在末尾不会加’\0’。所以 sizeof(p) == 6;并且一个有趣的问题是printf和cout直接输出p是不同的,printf是要碰到’\0’结束,我也看了printf和cout的汇编代码,可是没有细究,之后又空具体研究一下

(2)p1和p2的sizeof不同。由于一个是指针,一个是字符数组。指针在Win32编译环境下的sizeof都是4。由于是4字节的地址。32bits可寻址空间

(3)p3是还有一个有趣的问题,p3不能写成p3[3][]来初始化,由于这样初始化要保证二维数组每一行的个数同样。也就是不能出现“參差不齐”的情况,那种情况要动态分配

(4)这是一个陷阱

int a = 0;
cout<<sizeof(a=3)<<endl;
cout<<a<<endl;

输出为什么是4。0 而不是期望中的4。3???就在于sizeof在编译阶段处理的特性。由于sizeof不能被编译成机器码。所以sizeof作用范围内,也就是()里面的内容不能被编译,而是被替换成类型。=操作符返回左操作数的类型。所以a=3相当于int,而代码也被替换为:

cout<<4<<endl;
cout<<a<<endl;

所以,sizeof是不可能支持链式表达式的。这也是和一元操作符不一样的地方。

不要把sizeof当成函数,也不要看作一元操作符,把他当成一个特殊的编译预处理。

(5)这种原因是999999是一个编译器int型能够搞定的数。所以按int来处理,太大的数不能用int搞定,可是8个字节一定能够搞定的

sizeof(999999) == 4

sizeof(9999999999999999999) == 8

(6)最后是看了(9 / 5)编译器是作为int看待的。强制转换后才是double

三、sizeof 能总结多少是多少

sizeof博大精深。即使看了非常多资料,一口气总结完也是不可能了,总结经常使用的就好。

1、什么是sizeof

首先看一下sizeof在msdn上的定义:

The sizeof keyword gives the amount of storage, in bytes, associated with a variable or a type (including aggregate types). This keyword returns a value of type size_t.

看到return这个字眼,是不是想到了函数?错了,sizeof不是一个函数。你见过给一个函数传參数,而不加括号的吗?sizeof能够,所以sizeof不是函数。网上有人说sizeof是一元操作符。可是我并不这么觉得,由于sizeof更像一个特殊的宏,它是在编译阶段求值的。

举个样例:

cout<<sizeof(int)<<endl; // 32位机上int长度为4
cout<<sizeof(1==2)<<endl; // == 操作符返回bool类型。相当于 cout<<sizeof(bool)<<endl;
在编译阶段已经被翻译为:
cout<<4<<endl;
cout<<1<<endl;

2、语法

sizeof有三种语法形式。例如以下:

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

2) sizeof( type_name ); // sizeof( 类型 );

3) sizeof object; // sizeof 对象;

所以,

int i;

sizeof( i ); // ok

sizeof i; // ok

sizeof( int ); // ok

sizeof int; // error

既然写法1能够全然代替写法3,为求形式统一以及降低我们大脑的负担,第3种写法。忘掉它吧!

实际上。sizeof计算对象的大小也是转换成对对象类型的计算。也就是说,同种类型的不同对象其sizeof值都是一致的。这里,对象能够进一步延伸至表达式,即sizeof能够对一个表达式求值。编译器依据表达式的终于结果类型来确定大小,一般不会对表达式进行计算。

如:

sizeof( 2 ); // 2的类型为int。所以等价于 sizeof( int );

sizeof( 2 + 3.14 ); // 3.14的类型为double,2也会被提升成double类型。所以等价于 sizeof( double );

3、函数的sizeof

函数类型

考虑以下的问题:
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; // 错误。无法对void类型使用sizeof
cout<<sizeof(f1)<<endl; // 错误!无法对函数指针使用sizeof
cout<<sizeof*f2<<endl; // *f2,和f2()等价,由于能够看作object,所以括号不是必要的。被觉得是double

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

4、数组的sizeof

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=80
cout<<sizeof(c)<<endl; // 6

数组a的大小在定义时未指定。编译时给它分配的空间是依照初始化的值确定的。也就是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。

差点儿相同也要结束了,假设更进一步了解,须要查阅很多其它的资料~~~

—END—


參考文献

[1] http://blog.csdn.net/freefalcon/article/details/54839

[2] http://www.cnblogs.com/wanghetao/archive/2012/04/04/2431760.html

sizeof小览的更多相关文章

  1. Network Embedding 论文小览

    Network Embedding 论文小览 转自:http://blog.csdn.net/Dark_Scope/article/details/74279582,感谢分享! 自从word2vec横 ...

  2. anaconda 命令小览

    一 查看conda环境中安装了什么库: conda list 参考文献: 怎么查看anaconda安装了什么库?-Python学习网

  3. 数据类型 scanf标准函数 sizeof关键字 二进制(day03)

    字符类型的名称是char 字符类型里包含256个不同的整数,每个 整数对应一个字符(例如'a', '^'等) 这些整数和字符完全可以互相替代 ASCII码表列出所有整数和字符的对应关系 ASCII码表 ...

  4. 成吨提高开发效率:Intellij Shortcuts精简子集与思维模式

    在线精简cheatsheet备查表:intellij.linesh.twGithub项目:intellij-mac-frequent-keymap Intellij的快捷键多而繁杂,从官方推荐的key ...

  5. nodejs与v8引擎

    Motivation JavaScript 是一款拥有「自动垃圾回收」功能的编程语言. 市面上具有这样功能的语言,一般都是拥有相对应的虚拟机的,像 Java的JVM ,C#的CLR ,PHP的Zend ...

  6. zen coding一个牛的不行的html和css开发工具

    zen coding 是一种仿css选择器的语法来快速开发html和css的开源项目.现已更名为Emmet.可以到github上下载拜读.在这个都想偷懒的世界里,此方法可以极大的缩短开发人员的开发时间 ...

  7. C++常考面试题

    1 new/delete 与 malloc/free的区别 运算符是语言自身的特性,有固定的语义,编译器知道意味着什么,由编译器解释语义,生成相应的代码. 库函数是依赖于库的,一定程度上独立于语言的. ...

  8. Network Embedding

    网络表示 网络表示学习(DeepWalk,LINE,node2vec,SDNE) https://blog.csdn.net/u013527419/article/details/76017528 网 ...

  9. 我也来谈谈使用Zen Coding快速开发html和css原理

    zen coding 是一种仿css选择器的语法来快速开发html和css的开源项目.现已更名为Emmet.可以到github上下载拜读.在这个都想偷懒的世界里,此方法可以极大的缩短开发人员的开发时间 ...

随机推荐

  1. .Net实战之反射相关类之间的人体经络关系

    --1.类的部分组成成员 --2.巧记成员之间的关系 [MyTable("T_UserInfo")] public class UserInfo : Person, UserSer ...

  2. mvc使用linq to sql进行sum统计遇到查询为null的问题

    mvc linq to sql,linq to entity,sum,null 昨天写了段sum的统计语句, decimal sums sums = ( from fac in db.Apply wh ...

  3. Shell script之How to write

    Write shell script: 1) Editor like vi or mcedi 2) Set execute permission for your script chmod  perm ...

  4. 【CImg】基本像素操作

    继openCV之后接触的又一个C++视觉库——短小精干的CImg 刚开始接触的时候真的是..几乎无从下手,网上资料比较少,但发现有一篇非常有用的中文手册:http://wenku.baidu.com/ ...

  5. 前端JavaScript入门——JavaScript变量和操作元素

    变量JavaScript 是一种弱类型语言,javascript的变量类型由它的值来决定. 定义变量需要用关键字 ‘var’: var a = 123; var b = 'asd'; //同时定义多个 ...

  6. bzoj3940 censoring 题解(AC自动机)

    题目描述 Farmer John has purchased a subscription to Good Hooveskeeping magazine for his cows, so they h ...

  7. 微信小程序 客服自动回复图片

    产品需求是,在客服对话框里,发送特定的文字,回复我们的二维码: 小城程开发完成后,这个自动回复图片的功能就摆在了眼前.刚开始我们想到的是:在线客服功能的设置里设置好自动回复的图片,但是目前设置不支持自 ...

  8. <东方梦符祭> N1无尽30波终于通了

    嘛也算是第一次通关 纪念一下 阵容:xjb搭的杂牌队 主C:古明绝恋 露米娅(真·R卡战神)比那名居天子 斯卡雷特 控制:琪露诺 蕾蒂 灵梦 挂件:小伞 纳兹琳 古明地觉 永江依玖 第一发就直接抽到了 ...

  9. Docker私有仓库的构建

    [root@localhost ~]# vim /etc/sysconfig/docker #INSECURE_REGISTRY='--insecure-registry' INSECURE_REGI ...

  10. Python常用的内建模块

    PS:Python之所以自称“batteries included”,就是因为内置了许多非常有用的模块,无需额外安装和配置,即可直接使用.下面就来看看一些常用的内建模块. 参考原文 廖雪峰常用的内建模 ...