C/C++ 中,sizeof() 是一个判断数据类型或者表达式长度的运算符。

1 sizeof 定义

sizeofC/C++ 中的一个操作符(operator),返回一个对象或者类型所占的内存字节数。

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.                                                                                              ——来自MSDN

其返回值类型为 size_t ,在头文件 stddef.h 中定义为: typedef unsigned int size_t;

sizeof 的定义可以看出:sizeof 不是一个函数,因为函数调用必须有一对括号。

#include 

int main(void){   int num = 97;

   printf("sizeof(num = 0)的值:%d\n",sizeof(num = 0));      printf("num 的值:%d\n",num);      return 0;}

运行结果为4,97;并不是4,0

说明:sizeof 不是标准意义上的一元操作符,不支持链式表达式,sizeof 作用域范围内的语句不会编译成机器码,如 sizeof(num++) 中的 ++ 不执行。sizeof 也不是函数, sizeof 更像一个特殊的宏,在编译阶段求值。

2 sizeof 用法

sizeof 有两种语法形式,如下:

sizeof(type_name);    //sizeof(类型);sizeof (object);      //或sizeof object 都属于 sizeof对象;

所以:

int i;sizeof(i);    //合理sizeof i;     //合理sizeof(int);  //合理sizeof int;   //不合理
  • 对类型使用 sizeof 时,sizeof type_name 是非法的,必须写为 sizeof(type_name);
  • 无论是对对象还是类型取值,sizeof () 这种形式都是对的;

1 基本数据类型的 sizeof

这里的基本数据类型是指short、int、long、float、double这样的简单内置数据类型。

由于它们的内存大小是和系统相关的,所以在不同的系统下取值可能不同。

#include using namespace std;

int main(){   cout <"Size of char : " <   cout <"Size of int : " <   cout <"Size of short int : " <   cout <"Size of long int : " <   cout <"Size of float : " <float) <   cout <"Size of double : " <   cout <"Size of wchar_t : " <   return 0;}

在 32 位系统下内置数据类型与其 sizeof 运算结果如下:

Size of char : 1Size of int : 4Size of short int : 2Size of long int : 4Size of float : 4Size of double : 8Size of wchar_t : 4
  • unsigned 不影响内置类型 sizeof 的取值

2 指针类型的 sizeof

指针主要用于存储地址,前几天文章C语言指针详解提到过,指针变量的位宽等于机器字长,机器字长由 CPU 寄存器位数决定。在 32 位系统中,一个指针变量的返回值为 4 字节, 64 位系统中指针变量的 sizeof 结果为 8 字节。

char *p =”hello”; sizeof( p );       // 结果为4 sizeof(*p);        // 结果为1 int *pi; sizeof( pi );      //结果为4 sizeof(*pi);       //结果为4 char **pp = &p; sizeof( pp );      // 结果为4 sizeof( *pp );     // 结果为4 
  • 指针变量的 sizeof 值与指针所指的对象类型没有任何关系,与指针申请多少空间没有关系,所有的指针变量所占内存大小均相等。
  • 如果使用 32 位编译器编译得到程序是 32 位,那么在 64bits 系统下,指针变量大小仍然是 4 个字节。

3 函数类型的 sizeof

函数类型以其返回类型作为自身类型,进行 sizeof 取值。

void fun1(){}int fun2(){   return 0;}double fun3(){   return 0.0;}cout << sizeof(fun1()) << endl;  //错误!无法对void类型使用sizeofcout <cout <
  • 注意:不能对返回 void 函数和函数指针进行 sizeof 取值。

4 数组类型的 sizeof

sizeof 作用于数组时,求取的是数组所有元素所占用的大小。

    int A[3][5];    char c[]="abcdef";    double*(*d)[3][6];

    cout<    cout<    cout<    cout<    cout<    cout<    cout<    cout<    cout<

A 的数据类型是 int[3][5]A[4] 的数据类型是 int[5],A[0][0]数据类型是 int 。所以:

sizeof(A)==sizeof(int[3][5])==3*5*sizeof(int)==60sizeof(A[4])==sizeof(int[5])=5*sizeof(int)==20sizeof(A[0][0])==sizeof(int)==4

如果字符数组表示字符串,数组末自动插入 '\0',所以 c 的数据类型是 char[7] ,所以 sizeof(c)=sizeof(char[7])==7

d 是一个很奇怪的定义,他表示一个指向 double*[3][6] 类型数组的指针。既然是指针,所以 sizeof(d) 就是4。

既然 d 是执行 double*[3][6] 类型的指针, *d 就表示一个 double*[3][6] 的多维数组类型,因此 sizeof(*a)=3*6*sizeof(double*)=72

**d 表示一个 double*[6] 类型的数组,所以 sizeof(**d)=6*sizeof (double*)=24

***d 表示其中的一个元素,也就是 double* ,所以 sizeof(***d)=4

****d 是一个 double ,所以 sizeof(****d)=sizeof(double)=8

当数组作为函数形参时,下面输出结果应该是多少呢?

int GetStrLength(char str[]){   return sizeof(str);}

int main(){   char szStr[] = "abcdef";   cout<   return 0;}

输出不是 7 ,这里函数参数 str[] 已不再是数组类型,而是蜕变成指针,我们调用函数 GetStrLength() 时,程序会在栈上分配一个大小为 7 的数组吗?不会!数组是“传址”的,调用者只需将实参的地址传递过去,所以 str 自然为指针类型 (char*) ,输出值为:4 。

  • 数组的大小是各维数的乘积*数组元素的大小。
  • 向函数形参传递数组,数组将会退化为指针,失去原来数组的特性。

4 结构体类型的 sizeof

对于 struct 数据结构由 CPU 的对齐问题导致 struct 的大小变得比较复杂。具体可以查看以前的文章一文轻松理解内存对齐。

理论上,int 占 4byte , char 占一个 byte ,那么将它们放到一个结构体中应该占 4+1=5byte ;但是实际上,通过运行程序得到的结果是 8byte 。

#include

struct{    int x;    char y;}Test;

int main(){    printf("%d\n",sizeof(Test)); // 输出8不是5    return 0;}

结构体的大小跟结构体成员对齐有密切关系,而并非简单地等于各个成员的大小之和!比如对如下结构体两个结构体 A、B 使用 sizeof 的结果分别是:16,24。可以看出 sizeof(B) 并不等于 sizeof(int)+sizeof(double)+sizeof(int)=16

struct A{  int num1;  int num2;  double num3;};struct B{  int num1;  double num3;  int num2;};

结构体A和B中包含的成员都一样,只不过顺序不同而已,为什么其大小不一样呢?要解释这个问题,就要了解结构体成员对齐的规则。

  • 结构体的大小等于结构体内最大成员大小的整数倍
  • 结构体内的成员的首地址相对于结构体首地址的偏移量是其类型大小的整数倍,比如说 double 型成员相对于结构体的首地址的地址偏移量应该是 8 的倍数。
  • 为了满足规则 1 和 2 编译器会在结构体成员之后进行字节填充!

从三个规则我们来看看为什么 sizeof(B) 等于 24 :首先假设结构体的首地址为0,第一个成员 num1 的首地址是 0 (满足规则2),它的类型是 int ,因此它占用地址空间 0——3 。第二个成员 num3 是 double 类型,它占用 8 个字节,由于之前的 num1 只占用了 4 个字节,为了满足规则 2 ,需要使用规则 3 在 num1 后面填充 4 个字节(4——7),使得 num3 的起始地址偏移量为 8 ,因此 num3 占用的地址空间是:8——15。第三个成员 num2 是 int 型,其大小为 4 ,由于 num1 和num3 一共占用了 16 个字节,此时无须任何填充就能满足规则 2。因此 num2 占用的地址空间是 16——19 。那么是不是结构体的总大小就是 0——19 共 20 个字节呢?请注意,别忘了规则1!由于结构体内最大成员是 double 占用 8 个字节,因此最后还需要在 num2 后面填充 4 个字节,使得结构体总体大小为 24 。

struct S{ }; sizeof(S); // 结果为1
  • 对于一个空 struct 结构体取 sizeof 运算,运算结果为 1 并非 0 。因为编译器为保证此空 struct 存在,专门分配一个字节。
  • 如果存在结构体嵌套,无论内层还是外层均需要采用内存对齐。

5 类的 sizeof

  1. 不含继承和 static 成员变量的类。

在这种情况下,只需要考虑对齐方式即可。

class A {   public:   int b;   float c;   char d; };class B{ };

int main(void) {   cout <  //输出结果为12  cout <  //输出结果为1  return 0 ; }
  • 空的 class 同样也占用 1 个字节。
  • 计算类对象的大小时,类成员函数不占用对象空间,只需要考虑类中数据成员的大小。
  1. 类中存在静态成员变量
class A {   public:   static int a;   int b;   float c;   char d; };

int main() {   A object;   cout <  //输出结果为12  return 0 ; }

因为在程序编译期间,就已经为 static 变量在静态存储区域分配了内存空间,并且这块内存在程序的整个运行期间都存在。而每次声明了类 A 的一个对象的时候,为该对象在堆上,根据对象的大小分配内存。

  1. 类中包含成员函数
class A {   public:   static int a;   int b;   float c;   char d;   int add(int x,int y)   {     return x+y;   } };

int main() {   A object;   cout <  b = object.add(3,4);   cout <  //输出结果为12  return 0 ; }

因为只有非静态类成员变量在新生成一个object的时候才需要自己的副本。所以每个非静态成员变量在生成新object需要内存,而function是不需要的。

3 sizeofstrlen 区别

  • sizeof 是一个操作符,strlen 是库函数。
  • sizeof 的参数可以是数据的类型,也可以是变量,而 strlen 只能以结尾
  • 编译器在编译时就计算出了 sizeof 的结果,而 strlen 函数必须在运行时才能计算出来。并且 sizeof 计算的是数据类型占内存的大小,而 strlen 计算的是字符串实际的长度。
  • 数组做 sizeof 的参数不退化,传递给 strlen 就退化为指针了。如:
 int ss[20]="0123456789"; sizeof(ss)=80, //ss表示在内存中的大小,20*4。 strlen(ss)    //错误,strlen的参数只能是char*,且必须是以“\0”结尾的。 char *ss="0123456789"; sizeof(ss)=4,  //ss是指向字符串常量的字符指针。 sizeof(*ss)=1, // *ss是第一个字符。

参考资料

  1. https://www.cnblogs.com/Western-Trail/p/10326180.html
  2. 《C/C++实践进阶之道》

点【在看】是最大的支持 

c char转int_C/C++基础之sizeof使用相关推荐

  1. c char转int_c/c++基础之sizeof用法

    在 C/C++ 中,sizeof() 是一个判断数据类型或者表达式长度的运算符. 1 sizeof 定义 sizeof 是 C/C++ 中的一个操作符(operator),返回一个对象或者类型所占的内 ...

  2. sizeof 头文件_c/c++基础之sizeof用法

    在 C/C++ 中,sizeof() 是一个判断数据类型或者表达式长度的运算符. 1 sizeof 定义 sizeof 是 C/C++ 中的一个操作符(operator),返回一个对象或者类型所占的内 ...

  3. c char转int_C指针精华知识大汇总

    指针在C语言中是一块很重要的内容,也是比较难理解的一块内容,我们需要反复理解反复巩固才可以对其有所了解.之前也分享过指针相关的笔记,但是都比较杂,本篇笔记汇总一下指针相关的内容,包含了挺多指针相关的基 ...

  4. c语言 char转int_C语言关键字及进制的转换你都知道吗?

    ​前面我们讲过 C语言简洁.紧凑 使用方便.灵活 那是什么使得C语言这么方便呢? 那就是关键字,或称保留字 C语言的关键字共有32个 根据关键字的作用 可分为 数据类型关键字 控制语句关键字 存储类型 ...

  5. 装水体积c语言,C语言基础之--sizeof()运算符的使用以及注意

    sizeof是运算符,可用于任何变量名.类型名或常量值,当用于变量名(不是数组名)或常量时,它不需要用圆括号.它在编译时起作用,而不是运行时.让我们先看一个结构体: struct S1{ char c ...

  6. 黑马程序员--C语言基础之--sizeof()运算符的使用以及注意

    ------- IOS培训期待与您交流! ---------- sizeof是运算符,可用于任何变量名.类型名或常量值,当用于变量名(不是数组名)或常量时,它不需要用圆括号.它在编译时起作用,而不是运 ...

  7. C语言基础之--sizeof()运算符的使用以及注意

    sizeof是运算符,可用于任何变量名.类型名或常量值,当用于变量名(不是数组名)或常量时,它不需要用圆括号.它在编译时起作用,而不是运行时.让我们先看一个结构体: struct S1{char c; ...

  8. c char转int_C/C++ 各数据类型占用字节数

    第一次写文章,有点小激动,主要的目的是将正在学习的知识记录一下,方便随时复习,也给跟我一样正在学习C++的同学分享一下我的学习过程,博客中所用的知识都是我在网上或者书上查到的(其实我已经学过一段时间 ...

  9. c char*转int_C语言中的char类型也有signed和unsigned?字符也有正负之分吗?

    C语言中的 unsigned int 和 signed int 类型的区别,相信即使是初学者也是清楚的,无非就是最高位是否用来做符号位而已.但是最近有读者问我,为什么 char 类型也要区分 unsi ...

  10. java byte char io流_Java基础进阶 IO流之字节流

    1.IO流 1.1.概述 之前学习的File类它只能操作文件或文件夹,并不能去操作文件中的数据.真正保存数据的是文件,数据是在文件中.而File类它只是去对文件本身做操作,不能对文件中的数据进行操作. ...

最新文章

  1. MariaDB主从复制、主主复制
  2. AI佳作解读系列(一)——深度学习模型训练痛点及解决方法
  3. Django POST请求错误
  4. 技术 | Python从零开始系列连载(二十九)
  5. 软件开发工具(第1章:绪论)
  6. JDom,jdom解析xml文件
  7. 怎么挖linux内核的漏洞,linux内核漏洞分析实战看看专家是怎么一步步...-卓优商学院问答...
  8. 图表(Chart Graph)你真的用对了吗?
  9. 阶段性总结、反思、计划
  10. 40题计算机程序设计基础(C语言)编程习题
  11. 惠普win7驱动_win7怎么样打开无线网卡开关
  12. 软件工程总结笔记——软件结构设计(四)
  13. 五线谱软件测试初学者,学习五线谱(初学者专用).pdf
  14. 实习日记5:过滤器+批量删除+角色管理
  15. 网站搬家,服务器迁移注意事项有哪些?
  16. 准确测试身高的软件,情侣身高对比软件-身高模拟对比软件预约 v1.0最新版_5577安卓网...
  17. throttle在程序中的作用
  18. css ime-mode控制输入全角和半角
  19. cv.resize()详解
  20. 纯前端实现发送邮件(formspree + vue + elementui )

热门文章

  1. NodeJS Stream 五:双工流
  2. 关于STM32L100xx, STM32L151xx, STM32L152xx ,STM32L162xx 的Power Control
  3. 性能测试负载模型(八)
  4. java验证码(采用struts2实现)
  5. 使用Underscore.js的template将Backbone.js的js代码和html代码分离
  6. 持久化消息队列memcacheq的安装配置
  7. 关于支付宝授权登录获取用户信息
  8. python程序内存分析_Python中使用MELIAE分析程序内存占用实例
  9. C# 递归实现tree view(树结构)
  10. 小白自定义bat文件一键启动电脑应用