程序员iOS 面试题寒哥管理的技术专题

05·iOS 面试题·Sizeof与Strlen的区别与联系

2018-09-27  本文已影响9人  pengxuyuan

前言

sizeof()strlen() 在平时开发中使用的频率相对没那么高,个人觉得简单了解它们的用法及区别就 OK 了;最近刚好遇到一个用 sizeof() 计算结构体占用内存空间的问题,我们顺便也扯一扯这个吧。

这篇文章首先我们简单讲一下 sizeof()strlen() 的区别,然后了解下基本变量类型在 iOS 中占用多少内存空间,然后再扯一下如何计算结构体占用的内存空间大小,进而引申出字节对齐这个机制;最后总结在编写结构体的时需要注意的点。

sizeof() 跟 strlen() 的区别

简单来说: sizeof() 是运算符,在编译时期计算参数占用多少内存空间大小;strlen() 是一个函数,在运行时计算字符串的长度;

所以我感觉就是两个东西,也不是很清楚这两个有什么联系,不知道为什么会有这样奇怪的题目,可能我还没 get 到点吧,有人知道还望请告知。

基本数据类型在 iOS 中占用内存空间大小问题

这里直接用表格列举出来吧:

基本数据类型 32 位系统占用字节数 64位系统占用字节数
char 1 1
char * 4 8
short int 2 2
int 4 4
unsigned int 4 4
long 4 8
long long 8 8
unsigned long long 8 8
float 4 4
Double 8 8

结构体占用内存空间大小问题

为了更加清晰了解结构体占用内存空间的问题,我们先来分析下面代码示例:

typedef struct
{
    char  member1; //1字节
    short member2; //2字节
    int   member3; //4字节
}Family;

typedef struct
{
    char  member1; //1字节
    int   member3; //4字节
    short member2; //2字节
}Family2;

NSLog(@"Family size is %zd",sizeof(Family));
NSLog(@"Family2 size is %zd",sizeof(Family2));
//Family size is 8
//Family2 size is 12

看到 Log 结果,我们可能有两个疑问:

  1. 为什么 size 结果不是 7
  2. 两个结构体成员变量是一样的,顺序不同为什么会导致 size 不一样

这里其实涉及到了内存对齐,我们就简单说下需要内存对齐的原因以及内存对齐的规则,再详细的知识点可以看下文末的参考链接。

首先变量存放在内存中是不能随意存的,需要有一定的规则,在特定的地址才能存放特定的变量,这就导致变量在内存空间上不是简单的排序排列,需要一定的规则,为了达到这个规则,我们就需要内存对齐。

内存对齐的原因:

  1. 某些平台只能在特定的地址访问特定类型的数据
  2. 提高存取数据的速度

结构体内存对齐规则,摘抄自 一张图理解内存对齐

  1. 结构体中的第一个成员的首地址也即是结构体变量的首地址。
  2. 结构体中的每一个成员的首地址相对于结构体的首地址的偏移量(offset)是该成员数据类型大小的整数倍。
  3. 结构体的总大小是对齐模数(对齐模数等于#pragma pack(n)所指定的n与结构体中最大数据类型的成员大小的最小值)的整数倍。

通过上面规则我们可以很轻松的计算出上面代码结构体占用的大小:

typedef struct
{
    char  member1; //1字节
    short member2; //2字节
    int   member3; //4字节
}Family;

// 对于这个结构体:1+`1`+2+4 = 8字节 `1` 是补齐字节

typedef struct
{
    char  member1; //1字节
    int   member3; //4字节
    short member2; //2字节
}Family2;

// 对于这个结构体:1+`3`+4+2+`2` = 12字节,`3` 和 `2` 是补齐字节

这里可能有点晦涩难懂,大家可以具体看看这篇博客:C语言 - 结构体所占字节数 ,我这里再摘抄的话,也没什么意思;

反正对于计算结构体占用内存大小,大家需要注意有内存对齐这个东西就好了。

编写结构体注意事项

对于结构体占用内存空间这个,不是我们程序的性能瓶颈,但是学完这个面试题,我觉得掌握以下两个点挺好的:

  1. 写结构体时,尽量将成员变量按照占用内存空间从小到大排序
  2. 面对一些源码时,可以知道手动内存补齐这东西

例如下面 RunLoop 源码, _padding[3] 这个成员变量没有实际的意义,只是用来内存补齐的。

struct __CFRunLoopMode {
    CFRuntimeBase _base;
    pthread_mutex_t _lock;  /* must have the run loop locked before locking this */
    CFStringRef _name;
    Boolean _stopped;
    char _padding[3];
    CFMutableSetRef _sources0;
    CFMutableSetRef _sources1;
    CFMutableArrayRef _observers;
    CFMutableArrayRef _timers;
    //……
};

总结

这篇文章只是简单的说了下 sizeof()strlen() 的区别,然后聊了下将最近遇到结构体计算内存空间大小的问题,认识到了还有内存对齐这个东西;

感觉这篇有点水,主要还是说引申一些知识点,增加下知识的广度吧,对于我自己还是学到了一些的,关于更深度的东西,依旧,参考文献很优秀。

参考文献

iOS 笔试题 Sizeof与Strlen的区别与联系

C语言 - 结构体所占字节数

iOS32位和64位的坑

一张图正确理解内存对齐

iOS 内存字节对齐

https://www.jianshu.com/p/a371e2613ec8

iOS结构体的内存分配问题

C 语言结构体内存布局问题

C语言struct内存占用问题

上一篇 下一篇

猜你喜欢

热点阅读