各类数据类型sizeof的大小

2023-11-05

前言

之前总是误认为指针变量的大小和指针所指向的对象有关系,搞网络驱动时,使用kmalloc做内存申请时发现了一些端倪,先简单介绍下sizeof:

  • sizeof 是一个关键字,它是一个编译时的运算符,用于判断变量或数据类型的字节大小。
  • sizeof 运算符可用于获取类、结构、共用体和其他用户自定义数据类型的大小。

sizeof有两种语法形式,如下:
1、sizeof(type_name);//sizeof(类型);
2、sizeof object;//sizeof对象;

下面先来看一段代码:

#include <stdio.h>  
#include <string.h>  
int main(int argc,char *argv[]){
        char str1[] = "hello";
        char str2[100] = "hello";
        int arr1[] = {3,1,4};
        
        char *ptr1 = "hello";
        const char *ptr2 = str1;
        int *ptr3 = arr1;
        
        printf("size of type : %ld,%ld,%ld,%ld\n",sizeof(char),sizeof(int),sizeof(size_t),sizeof(long));                                                       
        printf("size of type*: %ld,%ld,%ld,%ld\n",sizeof(char*),sizeof(int*),sizeof(size_t*),sizeof(long*));
        printf("size of arr_var: %ld,%ld,%ld\n",sizeof(str1),sizeof(str2),sizeof(arr1));
        printf("size of ptr_var: %ld,%ld,%ld\n",sizeof(ptr1),sizeof(ptr2),sizeof(ptr3));
        
        return 0;        
}       

运行结果:
在这里插入图片描述

1 数据类型的sizeof

sizeof(type_name)很简单,64位操作系统中char占1个字符,int占4个字符、size_t(unsigned long int)、long都是8个字符。

2 数据对象的sizeof

2.1 指针变量的sizeof

printf("size  of  type*  :%ld, %ld, %ld, %ld\n", sizeof(char*), sizeof(int*), sizeof(size_t*), sizeof(void*)) ; 

从输出中可以看出,无论指针类型是char*、int*、size_t*还是void*,大小均是输出全是8bytes。

通常,在32位计算机中,一个指针变量的返回值通常是4(bytes),在64位系统中指针变量的sizeof通常为8(bytes)
指针变量的sizeof值与指针所指的对象没有任何关系,正是由于所有的指针变量所占内存大小相等,之前做C++时,MFC消息处理函数使用两个参数WPARAM、LPARAM就能传递各种复杂的消息结构(使用指向结构体的指针)

2.2 数组的sizeof

char str1[] = "hello";
char str2[100] = "hello";
int arr1[] = {3,1,4};
printf("size of arr_var: %ld,%ld,%ld\n",sizeof(str1),sizeof(str2),sizeof(arr1));

str1是变长’字符串’,等价于 “hello\0”,加上字符末尾的NULL终止符,内存一共分配6个字节;
sizeof(str2) 的值是 100, 等价于 sizeof(char [100]) ,在内存中一共分配 1*100 个字节;
sizeof(arr1)的值是12,等价于sizeof(int[3]),每个int占4字节,三个共分配12字节。
很好理解,分配了多少bytes内存,sizeof就是多大

2.3 数组名和指针的关系

这里这里不得不提的是,数组和指针的关系,因为:
我们经常将数组名和指针交换使用,把指针当成数组,或者把数组名赋给指针,通过指针来访问数组成员。有些资料上说,“数组名本身就是一个指针,是一个常量指针,即arr等价于int* const arr,因此不能试图修改数组名的值”,甚至有些直接说“数组名就是指针”。
我的理解是这句话对了一半吧,数组名在作为左值时,只是一个符号,并不指向保存地址,但作为右值(函数形参)使用时,就可以当成指针使用

看下面的代码:

char str1[] = "hello";
char str2[100] = "hello";
int arr1[] = {3,1,4};
      
char *ptr1 = "hello";
const char *ptr2 = str1;
int *ptr3 = arr1;

printf("size of arr_var: %ld,%ld,%ld\n",sizeof(str1),sizeof(str2),sizeof(arr1));
printf("size of ptr_var: %ld,%ld,%ld\n",sizeof(ptr1),sizeof(ptr2),sizeof(ptr3));

执行结果:
在这里插入图片描述
可以看出数组的sizeof大小和指向该数组指针的sizeof的区别,数组的sizeof就是该数组分配的内存大小;而指针的sizeof和指向的对象并没有关系,由CPU的寻址位数决定

刚刚说当数组作为右值或者函数变量时,可以作为指针,下面代码可以来测试下:

void func1(char a1[3])                                                                                   
{
        size_t c1=sizeof(a1);
        printf("%ld\n",c1);
}
void func2(char a2[])
{
        size_t c2=sizeof(a2);
        printf("%ld\n",c2);
}

调用func1,func2,输出结果如下:
在这里插入图片描述
此时,函数参数a1已不再是数组类型,而是蜕变成指针,所以sizeof(a1)的值是8,而不是6,按址传参。

2.4结构体的sizeof

typedef struct {                                                                                         
        char c;
        int i;
} S1; 

可能有些初学的朋友,看到S1应该认为,char占1个字节,int占4个字节,所以sizeof(S1)=5;我们运行下就会发现sizeof(S1)=8;
结构体的sizeof也有点复杂,主要和“字节对齐”有关,编译器默认会对结构体进行处理,让宽度为4的基本数据类型(int等)都位于能被4整除的地址上,这样是为了加快计算机的处理速度,减少指令周期

当然也通过强制对齐的方式使结构体字节对齐。我经常用以下两种:

#pragma pack (1)    //pragma pack(n)按照n字节对齐
typedef struct {
        char c;
        int i;
}S2;
#pragma pack()		//取消自定义字节对齐

//attribute__ ((packed)) 的作用就是告诉编译器取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐

typedef struct {                                                                                         
        char c;
        int i;
}__attribute__((packed))S3;
printf("sizeof(S1) = %ld\nsizeof(S2) = %ld\nsizeof(S3) = %ld\n",sizeof(S1),sizeof(S2),sizeof(S3));

在这里插入图片描述
这里对结构题的sizeof指示简单介绍,没有深入探讨,有兴趣的小伙伴可以自行学习下。

2.5联合体的sizeof

联合体则是重叠式,各成员共享一段内存,所以整个联合体的sizeof也就是每个成员sizeof的最大值的对齐结果

typedef union {
int i;
char c;
int arr[2];
} U;

在联合体U中sizeof(arr)=8最大,即sizeof(U)=8。

3对sizeof的一点理解

sizeof() 是 返回一个类型的在内存中说占的字节数。 属于运算符 ,同为 运算符的还有 + 、-、*、/ 、%等。而这个是在编译时候就被执行,而非运行时候执行,一开始就已经是计算机被知道的。

C标准和实际上的编译器一开始就定义好了,在32位电脑中,int 占据 4 字节, char占据1字节;

也有人定义如下两个宏,对sizeof()进行代码的实现;但注意的是,这是网友使用宏来实现的,而非编译器正在的实现方式,只是对会我们理解sizeof()有所帮助;

//适用于非数组
#define _sizeof(T) ((size_t)((T*)0 + 1))
//适用于数组
#define array_sizeof(T) ((size_t)(&T+1)-(size_t)(&T))

这部分理解是学习了好些博客和书籍的一点想法,大家学习时也可以多看看其他人的理解。

实际上对sizeof的理解,如果能深入到编译器,看看编译器的代码将一目了然,我这里只是从现象分析了一下sizeof,感兴趣的同学可以深究一下,我只是看了一下代码,就不在此卖弄了。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

各类数据类型sizeof的大小 的相关文章

  • 类型中的属性名称必须是唯一的

    我正在使用 Entity Framework 5 并且有以下实体 public class User public Int32 Id get set public String Username get set public virtual
  • 机器Epsilon精度差异

    我正在尝试计算 C 中双精度数和浮点数的机器 epsilon 值 作为学校作业的一部分 我在 Windows 7 64 位中使用 Cygwin 代码如下 include
  • std::list 线程push_back、front、pop_front

    std list 线程安全吗 我假设不是这样 所以我添加了自己的同步机制 我认为我有正确的术语 但我仍然遇到问题 每个函数都由单独的线程调用 Thread1 不能等待 它必须尽可能快 std list
  • std::vector 与 std::stack

    有什么区别std vector and std stack 显然 向量可以删除集合中的项目 尽管比列表慢得多 而堆栈被构建为仅后进先出的集合 然而 堆栈对于最终物品操作是否更快 它是链表还是动态重新分配的数组 我找不到关于堆栈的太多信息 但
  • free 和 malloc 在 C 中如何工作?

    我试图弄清楚如果我尝试 从中间 释放指针会发生什么 例如 看下面的代码 char ptr char malloc 10 sizeof char for char i 0 i lt 10 i ptr i i 10 ptr ptr ptr pt
  • 传递给函数时多维数组的指针类型是什么? [复制]

    这个问题在这里已经有答案了 我在大学课堂上学习了 C 语言和指针 除了多维数组和指针之间的相似性之外 我认为我已经很好地掌握了这个概念 我认为由于所有数组 甚至多维 都存储在连续内存中 因此您可以安全地将其转换为int 假设给定的数组是in
  • 用于 FTP 的文件系统观察器

    我怎样才能实现FileSystemWatcherFTP 位置 在 C 中 这个想法是 每当 FTP 位置添加任何内容时 我都希望将其复制到我的本地计算机 任何想法都会有所帮助 这是我之前问题的后续使用 NET 进行选择性 FTP 下载 ht
  • 需要帮助优化算法 - 两百万以下所有素数的总和

    我正在尝试做一个欧拉计划 http projecteuler net问题 我正在寻找 2 000 000 以下所有素数的总和 这就是我所拥有的 int main int argc char argv unsigned long int su
  • 方程“a + bx = c + dy”的积分解

    在等式中a bx c dy 所有变量都是整数 a b c and d是已知的 我如何找到整体解决方案x and y 如果我的想法是正确的 将会有无限多个解 由最小公倍数分隔b and d 但我只需要一个解决方案 我可以计算其余的 这是一个例
  • 使用 C# 中的 CsvHelper 将不同文化的 csv 解析为十进制

    C 中 CsvHelper 解析小数的问题 我创建了一个从 byte 而不是文件获取 csv 文件的类 并且它工作正常 public static List
  • WcfSvcHost 的跨域异常

    对于另一个跨域问题 我深表歉意 我一整天都在与这个问题作斗争 现在已经到了沸腾的地步 我有一个 Silverlight 应用程序项目 SLApp1 一个用于托管 Silverlight SLApp1 Web 的 Web 项目和 WCF 项目
  • 结构体的内存大小不同?

    为什么第一种情况不是12 测试环境 最新版本的 gcc 和 clang 64 位 Linux struct desc int parts int nr sizeof desc Output 16 struct desc int parts
  • 两个类可以使用 C++ 互相查看吗?

    所以我有一个 A 类 我想在其中调用一些 B 类函数 所以我包括 b h 但是 在 B 类中 我想调用 A 类函数 如果我包含 a h 它最终会陷入无限循环 对吗 我能做什么呢 仅将成员函数声明放在头文件 h 中 并将成员函数定义放在实现文
  • 空指针与 int 等价

    Bjarne 在 C 编程语言 中写道 空指针与整数零不同 但 0 可以用作空指针的指针初始值设定项 这是否意味着 void voidPointer 0 int zero 0 int castPointer reinterpret cast
  • LINQ:使用 INNER JOIN、Group 和 SUM

    我正在尝试使用 LINQ 执行以下 SQL 最接近的是执行交叉联接和总和计算 我知道必须有更好的方法来编写它 所以我向堆栈团队寻求帮助 SELECT T1 Column1 T1 Column2 SUM T3 Column1 AS Amoun
  • C# 动态/expando 对象的深度/嵌套/递归合并

    我需要在 C 中 合并 2 个动态对象 我在 stackexchange 上找到的所有内容仅涵盖非递归合并 但我正在寻找能够进行递归或深度合并的东西 非常类似于jQuery 的 extend obj1 obj2 http api jquer
  • 在 WPF 中使用 ReactiveUI 提供长时间运行命令反馈的正确方法

    我有一个 C WPF NET 4 5 应用程序 用户将用它来打开某些文件 然后 应用程序将经历很多动作 读取文件 通过许多插件和解析器传递它 这些文件可能相当大 gt 100MB 因此这可能需要一段时间 我想让用户了解 UI 中发生的情况
  • 在OpenGL中,我可以在坐标(5, 5)处精确地绘制一个像素吗?

    我所说的 5 5 正是指第五行第五列 我发现使用屏幕坐标来绘制东西非常困难 OpenGL 中的所有坐标都是相对的 通常范围从 1 0 到 1 0 为什么阻止程序员使用屏幕坐标 窗口坐标如此严重 最简单的方法可能是通过以下方式设置投影以匹配渲
  • MySQL Connector C/C API - 使用特殊字符进行查询

    我是一个 C 程序 我有一个接受域名参数的函数 void db domains query char name 使用 mysql query 我测试数据库中是否存在域名 如果不是这种情况 我插入新域名 char query 400 spri
  • 现代编译器是否优化乘以 1 和 -1

    如果我写 template

随机推荐

  • vue导出pdf

    vue项目中导出pdf 纯前端操作 有很多时候我们需要在项目中导出pdf文件 其实是利用插件将vue组件渲染成图片 然后将图片添加到PDF文档进行导出 本文用到的插件是html2canvas和jsPDF 文章目录 vue项目中导出pdf 纯
  • 力扣226. 翻转二叉树(递归)

    力扣226 翻转二叉树 递归 翻转一棵二叉树 示例 输入 4 2 7 1 3 6 9 输出 4 7 2 9 6 3 1 递归 1 定义函数功能 函数功能 即这个递归原问题是 给出一颗树 然后翻转它 所以 函数可以定义为 ListNode r
  • Python字典中的值为列表或字典的构造方法

    1 值为列表的构造方法 dic dic setdefault key append value 示例如下 gt gt dic setdefault a append 1 gt gt dic setdefault a append 2 gt
  • 关于点击UIButton弹出键盘,并且键盘的上方还需添加UITextField或者UITextView的解决方法

    最近在做一个项目的时候 有这样一个需求 点击UIButton弹出键盘 键盘的上方还需添加一个输入框 UITextField UITextView 开始的想法是直接设置输入框的 inputAccessoryView 设置后发现键盘根本就没显示
  • 视频中的物理要素——提取人们产生共情的元素

    近几年油管 各种小视频的兴起 似乎在为我们打开一扇门 研究角度来看 人们为什么对小视频如此痴迷 短暂的欲望得到满足 为什么通过视觉刺激 听觉刺激可以在观看吃播的时候 观看者也可以得到同样的对食物满足的情绪刺激 很重要的原因是 我们很需要很需
  • 格式化字符串学习

    常见的格式化字符串函数 输出 函数 基本介绍 printf 输出到 stdout fprintf 输出到指定 FILE 流 vprintf 根据参数列表格式化输出到 stdout vfprintf 根据参数列表格式化输出到指定 FILE 流
  • c++ auto类型用法总结

    一 用途 auto是c 程序设计语言的关键字 用于两种情况 1 声明变量时根据初始化表达式自动推断该变量的类型 2 声明函数时函数返回值的占位符 二 简要理解 auto可以在声明变量时根据变量初始值的类型自动为此变量选择匹配的类型 举例 对
  • 安装Zookeeper和Kafka集群

    安装Zookeeper和Kafka集群 本文介绍如何安装Zookeeper和Kafka集群 为了方便 介绍的是在一台服务器上的安装 实际应该安装在多台服务器上 但步骤是一样的 安装Zookeeper集群 下载安装包 从官网上下载安装包 cu
  • LDAP 入门知识

    LDAP的基本概念 LDAP是轻量目录访问协议 Lightweight Directory Access Protocol 的缩写 是一种基于 客户机 服务器模式的目录服务访问协议 其实是一话号码簿 LDAP是一种特殊的数据库 LDAP 目
  • jpa方法名命名规则

    一 常用规则速查 1 And 并且2 Or 或3 Is Equals 等于4 Between 两者之间5 LessThan 小于6 LessThanEqual 小于等于7 GreaterThan 大于8 GreaterThanEqual 大
  • Auto.js实现i茅台自动化申购

    i茅台自动化申购 文章目录 i茅台自动化申购 前言 一 前提条件 二 代码示例 总结 前言 现在茅台行情十分火热 茅台集团推出了i茅台APP供大家申购 下面介绍使用Auto js实现自动化申购 一 前提条件 需要下载Auto js的apk
  • 40.1自定义组建el-cascader

    1 子组件
  • 51单片机模拟救护车的警报声

    include
  • React Hooks --useEffect

    再用class写组件时 经常会用到生命周期函数 来处理一些额外的事情 副作用 和函数业务主逻辑关联不大 特定时间或事件中执行的动作 比如请求后端数据 修改Dom等 在React HookS中也需要类似的生命周期函数 useEffect由此诞
  • t检验与方差分析的区别和联系

    一 t检验和方差分析的应用 1 t检验的应用 t检验主要用于比较两组数据之间的均值是否存在显著差异 例如比较两种手术方式对患者的术后疼痛程度是否有显著差异 在医学研究中 t检验可以用于比较不同手术方式或药物对患者的疗效差异 例如 我们可以采
  • kettle的下载安装以及问题点

    1 kettle下载以安装 1 kettle的官网下载地址 Pentaho from Hitachi Vantara Browse Files at SourceForge net 2 如果需要下载其他版本 直接点击对应的版本Name 8
  • 闪回数据归档+闪回数据归档区+创建闪回数据归档区+创建闪回数据归档区案例+为数据归档区添加表空间+为数据归档区删除表空间+数据归档区修改数据保留时间+删除数据归档区

    闪回数据归档 1 它将改变的数据另外存储到特定的闪回数据归档区中 从而让闪回不再受撤销数据的限制 提高数据的保留时间 2 闪回数据归档中的数据行可以保留几年甚至几一年 3 闪回数据归档并不针对所有的数据改变 它只记录update和delet
  • 小程序搭建mqtt服务器,微信小程序连接MQTT服务器实现控制Esp8266LED灯

    上一篇文章已实现Esp8266开发板与MQTT服务器连接实现控制LED灯 这篇文章记录继上篇的功能接入微信小程序实现LED灯的控制 先理解一个概念 微信小程序订阅MQTT服务器一个主题 Esp8266订阅相同的主题时 微信小程序发送给MQT
  • python raise

    当程序出现错误 python会自动引发异常 也可以通过raise显示地引发异常 一旦执行了raise语句 raise后面的语句将不能执行 演示raise用法 try s None if s is None print s 是空对象 rais
  • 各类数据类型sizeof的大小

    前言 之前总是误认为指针变量的大小和指针所指向的对象有关系 搞网络驱动时 使用kmalloc做内存申请时发现了一些端倪 先简单介绍下sizeof sizeof 是一个关键字 它是一个编译时的运算符 用于判断变量或数据类型的字节大小 size