C/C++ sizeof

news2024/11/29 8:44:14

介绍

sizeof 是一个关键字、操作符,也是一个编译时运算符

作用:返回一个对象或者类型所占的内存字节数

使用方法

sizeof(type_name);//sizeof(类型)
sizeof(object);//sizeof(对象)

注意:

sizeof 操作符不能用于函数类型,不完全类型或位字段

不完全类型:指具有未知存储大小的数据类型,如未知存储大小的数组类型、未知内容的结构或联合类型、void 类型……

sizeof(void) 不是正确形式

基本数据类型

本质:将对象转换成对象类型进行计算,同种类型的不同对象其 sizeof 值相同

常见字长:

#include <iostream>
#include <string>
using namespace std;
int main() {
    cout << "sizeof(bool)=" << sizeof(bool) << endl;				// 1	
    cout << "sizeof(char)=" << sizeof(char) << endl;				// 1	
    cout << "sizeof(short)=" << sizeof(short int) << endl;		    // 2
    cout << "sizeof(int)=" << sizeof(int) << endl;				    // 4
    cout << "sizeof(long)=" << sizeof(long int) << endl;			// 4
    cout << "sizeof(long long)=" << sizeof(long long) << endl;	    // 8
    cout << "sizeof(float)=" << sizeof(float) << endl;			    // 4
    cout << "sizeof(double)=" << sizeof(double) << endl;			// 8
    return 0;
}

表达式

编译器根据表达式的最终结果类型确定大小,sizeof 是编译时进行计算,与运行时无关,不会对表达式进行计算

#include <iostream>
#include <string>
using namespace std;
int main() {
    int i = 8;
    cout << "sizeof(i)=" << sizeof(i) << endl;					// 4
    cout << "sizeof(i=5)=" << sizeof(i = 5) << endl;		    // 4
    cout << i << endl;//sizeof(i = 5)不会改变i的值
    cout << "sizeof(i++)=" << sizeof(i++) << endl;		        // 4
    cout << i << endl;//sizeof(i++)不会改变i的值
    return 0;
}

指针

指针变量的 sizeof 值与指针所指的对象类型无关,与指针申请的空间大小无关,所有指针变量所占内存大小均相等

32 位系统中,返回 4;64 位系统中,返回 8

#include<iostream>
using namespace std;
char fun() {
	return 'c';
}
int main() {
    //指向char类型变量的指针
	char c;
	char* ptr_char = &c;
	cout << "sizeof(ptr_char) = " << sizeof(ptr_char) << endl;         // 8

	//指向int类型变量的指针
	int i;
	int* ptr_int = &i;
	cout << "sizeof(ptr_int) = " << sizeof(ptr_int) << endl;           // 8

	//指向double类型变量的指针
	double* ptr_double = new double[10];
	cout << "sizeof(ptr_double) = " << sizeof(ptr_double) << endl;     // 8

	//二级指针
	char** two_ptr_char = &ptr_char;
	cout << "sizeof(二级指针) = " << sizeof(two_ptr_char) << endl;      // 8

	//函数指针:指向函数的指针,指针函数:返回值是指针的函数
	void (*ptr_f)();
	cout << "sizeof(函数指针) = " << sizeof(ptr_f) << endl;             // 8

	//&fun:一个函数指针
    cout << "sizeof(&fun) = " << sizeof(&fun) << endl;                 // 8
 
	//fun():一次函数调用
	cout << "sizeof(fun()) = " << sizeof(fun()) << endl;// 1,返回返回值的类型的大小

	//(*fun)():一次函数调用
	cout << "sizeof((*fun)()) = " << sizeof((*fun)()) << endl;// 1,返回返回值的类型的大小
	return 0;
}

数组

数组所有元素所占用的大小

#include<iostream>
using namespace std;
void foo(int a[3]) {//当数组作为函数形参时,以指针类型进行传递
	cout << "sizeof(a) = " << sizeof(a) << endl;   // 8,a以指针传递,故a为指针
}

int main() {
    //二维数组
	int A[3][5];
	cout << "sizeof(A) = " << sizeof(A) << endl;                // 60=3*5*4,A的数据类型为int[3][5]
	cout << "sizeof(A[0]) = " << sizeof(A[0]) << endl;          // 20=5*4,A[0]的数据类型为int[5]
	cout << "sizeof(A[4]) = " << sizeof(A[4]) << endl;          // 20=5*4,A[4]的数据类型为int[5]
         //虽然A[4]下标越界,但sizeof只关心数据类型,在编译阶段已经完成,不会造成运行错误
	cout << "sizeof(A[0][0]) = " << sizeof(A[0][0]) << endl;    // 4=1*4,A[0][0]的数据类型为int
	cout << "sizeof(A[0][1]) = " << sizeof(A[0][1]) << endl;    // 4=1*4,A[0][1]的数据类型为int

	//字符串
	char c[] = "abcdef";
	cout << "sizeof(c) = " << sizeof(c) << endl;                // 7=6+1('\0')

	//指针数组=指针内存大小*元素个数
	char* ch[10];
	cout << "sizeof(ch) = " << sizeof(ch) << endl;       // 80,ch是一个数组,数组的元素是指针
	cout << "sizeof(*ch) = " << sizeof(*ch) << endl;     // 8,*ch是一个指针,是数组的第一个元素
	cout << "sizeof(**ch) = " << sizeof(**ch) << endl;   // 1,**ch是一个char变量,是数组的第一个元素(指针)指向的变量

	//数组指针
	int* (*d)[3][6];
	cout << "sizeof(d) = " << sizeof(d) << endl;         // 8,d是一个指针,指向一个二维数组,二维数组的元素是int类型的指针
	cout << "sizeof(*d) = " << sizeof(*d) << endl;       // 144=3*6*8,*d是一个二维数组,是d指向的二维数组
	cout << "sizeof(**d) = " << sizeof(**d) << endl;     // 48=6*8,**d是一个一维数组
	cout << "sizeof(***d) = " << sizeof(***d) << endl;   // 8,***d是一个指针
	cout << "sizeof(****d) = " << sizeof(****d) << endl; // 4,****d是一个int变量

	//一维数组
	int nums[] = { 1,2,3 };
	cout << "sizeof(nums) = " << sizeof(nums) << endl;   // 12=3*4
	foo(nums);//参数以指针传递
	return 0;
}

字符串

#include <iostream>
#include <string>
#include <cstring>
using namespace std;

int main() {
    const char* strPtr = "hyy";
    char strs[] = "hyy";
    string str = "h";
    cout << "sizeof(strPtr) = " << sizeof(strPtr) << endl;   // 8,strPtr是一个指针
    cout << "sizeof(strs) = " << sizeof(strs) << endl;       // 4,strs是一个字符数组,包括 '\0'
    cout << "sizeof(str) = " << sizeof(str) << endl;         // 40,str是一个string类对象,是string类所占的实际内存
    cout << "sizeof(string) = " << sizeof(string) << endl;   // 40

    cout << "strlen(strPtr) = " << strlen(strPtr) << endl;   // 3
    cout << "strlen(strs) = " << strlen(strs) << endl;       // 3
    cout << "str.size() = " << str.size() << endl;           // 1
    return 0;
}

函数

返回函数返回值类型的大小,函数并不会被调用执行

sizeof(函数名(实参表))

PS:

  1. 不可以对返回值类型为空的函数求值
  2. 不可以对函数名求值
  3. 对有参数的函数,须写上实参列表
#include <iostream>
using namespace std;

int intfun() {
    return 1;
}

double doufun(int a, double b) {
    return a + b;
}

void voidfun() { }

int main() {
    // cout << "sizeof(intfun) = " << sizeof(intfun) << endl;               //编译失败   
    cout << "sizeof(intfun()) = " << sizeof(intfun()) << endl;              // 4
    cout << "sizeof(doufun(1, 1.5)) = " << sizeof(doufun(1, 1.5)) << endl;  // 8,不可省略实参列表
    // cout << "sizeof(voidfun()) = " << sizeof(voidfun()) << endl;         //编译失败
    return 0;
}

结构体

内存对齐

对其目的:减少访存指令周期,提高 CPU 存储速度

一般情况下,结构体所占内存大小并非元素本身大小之和

#include <iostream>
using namespace std;

struct S1 {
    char c;
    int i;
};

int main() { 
    cout << "sizeof(S1) = " << sizeof(S1) << endl;   // 8
    return 0;
}

// sizeof(S1) =/= sizeof(char) + sizeof(int)

结构体或类成员变量具有不同类型时,需进行成员变量的对齐

每个特定平台上的编译器都有自己的默认“对齐系数”(对齐模数)

32 位机对齐(默认)是按4字节对齐,而 64 位机(默认)是按8字节对齐

模数在不同平台值不同,可使用#pragmapack(n)改变

对其原则:

  1. 结构体内存大小应按最大元素大小对齐,若最大元素大小超过模数,应按模数大小对齐
  2. 若结构体的最大元素大小超过模数,结构体的起始地址是可以被模数整除的;若最大元素大小没有超过模数,那么其起始地址是可以被最大元素大小整除
  3. 结构体每个成员相对于结构体首地址的偏移量都是成员大小的整数倍,若有需要编译器会在成员之间加上填充字节(internal adding),首个成员从偏移量为 0 的位置开始存
  4. 结构体的总大小为结构体最宽基本成员类型大小的整数倍,若有需要编译器会在最末一个成员之后加上填充字节(trailing padding)

空结构体(不含数据成员)的 sizeof 值为 1

静态成员存放在静态存储区,不占用结构体的大小

成员函数不占用结构体的大小

#include <iostream>
using namespace std;

struct st0 {
    char a;     // 1 + pad(7)
    char* a1;   // 8
    int c;      // 4 + pad(4)
};              // 24
//a 的长度为 1,所占的地址为 0;
//a1 的长度为 8,偏移前的首地址为 1,因为首地址不是成员大小的整数倍,故需偏移,使其首地址为 8 即可,故加上 7 个填充字节;
//c 的长度为 4,首地址为 16,结构体的大小为 20,不是最宽基本成员(8)的整数倍,故需填充 4 个字节,使得结构体总大小为 24

struct st1 {
    char a;     // 1 + pad(7)
    double b;   // 8
    int c;      // 4
    char d;     // 1 + pad(3)
};              // 24
// a 的长度为 1,所占的地址为 0;
// b 的长度为 8,偏移前的首地址为 1,因为首地址不是成员大小的整数倍,故需偏移,使其首地址为 8 即可,故加上 7 个填充字节;
// c 的长度为 4,首地址为 16
// d 的长度为 1,首地址为 20,结构体大小为 21,不是最宽基本成员(8)的整数倍,故需填充 3 个字节,使得结构体总大小为 24

struct st2 {
    char a;     // 1
    char a1;    // 1 + pad(2)
    int c;      // 4
    st1 st;     // 24
    char d;     // 1 + aad(7) 
};              // 40
// a 的长度为 1,所占的地址为 0;
// a1 的长度为 1,所占的地址为 1,首地址是成员大小的整数倍,故不需要偏移
// c 的长度为 4,偏移前的首地址为 2,因为首地址不是成员大小的整数倍,故需偏移,使其首地址为 4 即可,故加上 2 个填充字节;
// st 的长度为 24,首地址为 8,虽然首地址不是成员大小的整数倍,但因为成员大小超过默认模数,故以模数进行对齐
// d 的长度为 1,首地址为 32,结构体大小为 33,不是模数(8)的整数倍(因为最宽基本成员类型大小超过模数,故以模数进行对齐),故需填充 7 个字节,使得结构体总大小为 40

int main() { 
    cout << "sizeof(st0) = " << sizeof(st0) << endl;   // 24
    // 获取成员在结构体的地址偏移量
    cout << "offsetof(st0, a) = " << offsetof(st0, a) << endl;   // 0
    cout << "offsetof(st0, a1) = " << offsetof(st0, a1) << endl; // 8
    cout << "offsetof(st0, c) = " << offsetof(st0, c) << endl;   // 16

    cout << "sizeof(st1) = " << sizeof(st1) << endl;   // 24
    cout << "offsetof(st1, a) = " << offsetof(st1, a) << endl;   // 0
    cout << "offsetof(st1, b) = " << offsetof(st1, b) << endl;   // 8
    cout << "offsetof(st1, c) = " << offsetof(st1, c) << endl;   // 16
    cout << "offsetof(st1, d) = " << offsetof(st1, d) << endl;   // 20

    cout << "sizeof(st2) = " << sizeof(st2) << endl;   // 40
    cout << "offsetof(st2, a) = " << offsetof(st2, a) << endl;   // 0
    cout << "offsetof(st2, a1) = " << offsetof(st2, a1) << endl; // 1
    cout << "offsetof(st2, c) = " << offsetof(st2, c) << endl;   // 4
    cout << "offsetof(st2, st) = " << offsetof(st2, st) << endl; // 8
    cout << "offsetof(st2, d) = " << offsetof(st2, d) << endl;   // 32
   
    return 0;
}

进行 sizeof 计算时,类与结构体类似

  • 空类大小为 1
  • 类的成员函数不占用结构体大小。类对象的大小由其数据成员决定
  • 类和结构体一样,需要对齐
  • 类若包含虚函数,编译器会在类对象中插入一个指向虚函数表的指针(多个虚函数也只有一个),以帮助实现虚函数的动态调用
  • 静态成员存放在静态存储区,不占用类的大小
#include <iostream>
using namespace std;

class c0 {
    char a;     // 1 + pad(7)
    char* a1;   // 8
    int c;      // 4 + pad(4)
};              // 24

class c1 {
    char a;     // 1 + pad(7)
    double b;   // 8
    int c;      // 4
    char d;     // 1 + pad(3)
};              // 24

class c2 {
    char a;     // 1
    char a1;    // 1 + pad(2)
    int c;      // 4
    c1 cla;     // 24
    char d;     // 1 + pad(7) 
};              // 40

struct c3
{
    static int i;       // 静态成员
    int fun();          // 成员函数
    int d;              // 4
    char ch;            // 1 + pad(3)
    virtual int vir1(); // 8 (64bit)
};                      // 16

class A{};   // 1,空类

class B {
    virtual int fun(){   // 虚函数
        return 0;
    }
};                       // 8

class C {
    static int a;   // 静态成员
    void fun();     // 成员函数
};                  // 1

int main() { 
    cout << "sizeof(c0) = " << sizeof(c0) << endl;   // 24
    cout << "sizeof(c1) = " << sizeof(c1) << endl;   // 24
    cout << "sizeof(c2) = " << sizeof(c2) << endl;   // 40
    cout << "sizeof(c3) = " << sizeof(c3) << endl;   // 16

    cout << "sizeof(A) = " << sizeof(A) << endl;     // 1
    A a;
    cout << "sizeof(a) = " << sizeof(a) << endl;     // 1,空类的实例大小就是类的大小

    cout << "sizeof(B) = " << sizeof(B) << endl;     // 8
    B b;
    cout << "sizeof(b) = " << sizeof(b) << endl;     // 8

    cout << "sizeof(C) = " << sizeof(C) << endl;   // 1
    C c;
    cout << "sizeof(c) = " << sizeof(c) << endl;   // 1

    return 0;
}

string

sizeof(string)计算 string 变量在内存中的空间大小,与字符串长度无关

string 在内存中的布局:

vector

sizeof(vector)计算 vector 变量在内存中的空间大小,与变量中元素的个数无关

联合体

结构体在内存组织上是顺序式的,联合体是重叠式,各成员共享一段内存,所以整个联合体的 sizeof 就是每个成员 sizeof 的最大值

#include <iostream>
using namespace std;

class c {
    char a;     // 1 + pad(7)
    char* a1;   // 8
    int c;      // 4 + pad(4)
};              // 24

union U {
    int i;      // 4
    char c;     // 1
    class c c_c;// 24
};
int main() { 
    cout << "sizeof(U) = " << sizeof(U) << endl;   // 24
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1159904.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

爆肝将近 10 万字讲解 Node.Js 详细教程

1. Node.Js 环境概述 Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境&#xff0c;用于在服务器端运行 JavaScript。它使用了一个事件驱动、非阻塞式I/O的模型&#xff0c;使得其轻量且高效。Node.js 的包管理器 npm 是全球最大的开源库生态系统。Node.js 能够响应大…

Java架构师知识产权与标准化

目录 1 导学2 知识产权概述3 保护期限4 知识产权人的确定4 侵权判断5 标准划分想学习架构师构建流程请跳转:Java架构师系统架构设计 1 导学 2 知识产权概述 知识产权是指公民、法人、非法人单位对自己的创造性智力成果和其他科技成果依法享有的民事权。是智力成果的创造人依…

AI“走深向实”,蚂蚁蚁盾在云栖大会发布实体产业「知识交互建模引擎」

数字化起步晚、数据分散稀疏、专业壁垒高、行业知识依赖「老师傅」&#xff0c;是很多传统产业智能化发展面临的难题。2023年云栖大会上&#xff0c;蚂蚁集团安全科技品牌蚁盾发布“知识交互建模引擎”&#xff0c;将实体产业知识与AI模型有机结合&#xff0c;助力企业最快10分…

二进制基础

最近开始入坑系统安全大坑&#xff0c;调转方向开始了解pwn&#xff0c;那就要补一些那少得可怜的底层基础啦 先学几个单词&#xff1a; exploit&#xff1a;用于攻击的脚本与方案payload&#xff1a;攻击载荷&#xff0c;是目标进程被劫持控制流的数据&#xff08;精心构造的…

Python画图之HelloKitty

Python-turtle画出HelloKitty&#xff08;有趣小游戏&#xff09; 一、效果图二、安装库1.常用镜像源2.库下载 三、Python代码 一、效果图 二、安装库 1.常用镜像源 1. 豆瓣http://pypi.douban.com/simple/ 2. 清华大学&#xff1a;https://pypi.tuna.tsinghua.edu.cn/simple…

智能视频监控平台EasyCVR出现偶发通道在线,但是无法播放的情况要怎么解决?

视频云存储/安防监控EasyCVR视频汇聚平台基于云边端智能协同&#xff0c;支持海量视频的轻量化接入与汇聚、转码与处理、全网智能分发、视频集中存储等。流媒体视频平台EasyCVR拓展性强&#xff0c;视频能力丰富&#xff0c;具体可实现视频监控直播、视频轮播、视频录像、云存储…

Scrum of Scrums大规模敏捷管理流程

​​​​​​​Leangoo领歌​​​​​​​是一款永久免费的专业的敏捷开发管理工具&#xff0c;提供端到端敏捷研发管理解决方案&#xff0c;涵盖敏捷需求管理、任务协同、进展跟踪、统计度量等。 Leangoo领歌上手快、实施成本低&#xff0c;可帮助企业快速落地敏捷&#xff0c…

Linux学习之进程二

目录 进程状态 R (running)运行状态与s休眠状态&#xff1a; disk sleep&#xff08;深度睡眠状态&#xff09; T (stopped)&#xff08;暂停状态&#xff09; t----tracing stop(追踪状态) X死亡状态&#xff08;dead&#xff09; Z(zombie)-僵尸进程 孤儿进程 进程优…

Android问题

这里面要加入 ,加入前是点击待君登录直接跳回手机主界面了 加入上述代码即可 Android之Inflate() Inflate()作用就是将xml定义的一个布局找出来&#xff0c;但仅仅是找出来而且隐藏的&#xff0c;没有找到的同时并显示功能。 android上还有一个与Inflate()类似功能的…

【AI视野·今日CV 计算机视觉论文速览 第274期】Tue, 24 Oct 2023

AI视野今日CS.CV 计算机视觉论文速览 Tue, 24 Oct 2023 Totally 138 papers &#x1f449;上期速览✈更多精彩请移步主页 Interesting: &#x1f4da;Wonder3D, 基于交叉扩散模型的单图像三维形状生成。(from 香港大学) website:https://www.xxlong.site/Wonder3D/ Daily Co…

Flutter 04 按钮Button和事件处理、弹框Dialog、Toast

一、按钮组件 1、按钮类型&#xff1a; 2、按钮实现效果&#xff1a; import package:flutter/material.dart;void main() {runApp(const MyApp()); }class MyApp extends StatelessWidget {const MyApp({Key? key}) : super(key: key);overrideWidget build(BuildContext co…

X64(64位)汇编指令与机器码转换原理

X64&#xff08;64位&#xff09;汇编指令与机器码转换原理 1 64位寻址形式下的ModR/M字节1.1 寻址方式1.2 寄存器编号 2 汇编指令转机器码2.1 mov rcx, 1122334455667788h2.2 mov rcx,[r8]与mov [r8],rcx2.3 mov rcx,[r8r9*2] 本文属于《 X86指令基础系列教程》之一&#xff…

重温云栖,分享十年成长:我和云栖的故事

文章目录 前言活动背景我和云栖的交际历届峰会主题2009201020112012201320142015201620172018202120222023 技术带来的变化工作生活关注的领域 后记 前言 云栖大会&#xff0c;前身可追溯到2009年的地方网站峰会&#xff0c;2011年演变为阿里云开发者大会&#xff0c;2015年正式…

python线程(进程子单位)

进程是由CPU给分配的执行单元&#xff0c;比较消耗空间和内存 创建、使用线程 import threading# 进程 # 线程 from time import sleepdef download():list1 ["girl.png", "boy.png", "child.png"]for l in list1:print(l)sleep(1.5)print(&qu…

ThinkPad T14 2023评测|thinkpad t14 gen4

一、购买地址 我在淘宝、京东、联想商城、苏宁易购都看了看&#xff0c;最终确定了在抖音官方商城买电脑&#xff0c;主要是价格低&#xff0c;足足少了四百&#xff0c;还送了一个电脑包和一个鼠标。 二、硬件信息 2.1 内存 这个运行内存比较有意思&#xff0c;我还是第一次买…

前端JavaScript

文章目录 一、JavaScript概述JS简介1.ECMAScript和JavaScript的关系2.ECMAScript的历史3.什么是javas&#xff1f;4.JavaScript的作用&#xff1f; 三者之间的作用JS基础1.注释语法2.引入js的多种方式3.结束符号 变量与常量变量1.JavaScript声明2.var与let的区别常量 基本数据类…

【Linux进程】再谈软件—操作系统(Operator System)

目录 操作系统(Operator System) 概念 设计OS的目的 如何理解 "管理"——先描述再组织 系统调用和库函数概念 总结 操作系统(Operator System) 概念 任何计算机系统都包含一个基本的程序集合&#xff0c;称为操作系统(OS)。 笼统的理解&#xff0c;操作系统…

206. 反转链表、Leetcode的Python实现

博客主页&#xff1a;&#x1f3c6;看看是李XX还是李歘歘 &#x1f3c6; &#x1f33a;每天分享一些包括但不限于计算机基础、算法等相关的知识点&#x1f33a; &#x1f497;点关注不迷路&#xff0c;总有一些&#x1f4d6;知识点&#x1f4d6;是你想要的&#x1f497; ⛽️今…

Springboot+shiro,完整教程,带你学会shiro

您的第一个 Apache Shiro 应用程序 引入依赖&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLoc…

一文深入了解 CPU 的型号、代际架构与微架构

在 10 月 16 号的时候&#xff0c;Intel 正式发布了第 14 代的酷睿处理器。但还有很多同学看不懂这种发布会上发布的各种 CPU 参数。借着这个时机&#xff0c;给大家深入地讲讲 CPU 的型号规则、代际架构与微架构方面的知识。 CPU 在整个计算机硬件中、技术体系中都算是最最重…