swift4-汇编分析枚举内存布局

一、枚举的内存原理

1.1  常规case

enum TestEnum {
case test1, test2, test3 }
var t = TestEnum.test1
t = .test2
t = .test3

枚举是常规的case的情况-是采取一个字节来存枚举变量


通过拿到枚举的内存地址,看地址里面存的枚举值情况窥探枚举内存存储情况
var t = TestEnum.test1 //内存存的是0 0x00000001000106e0 00 00 00 00 00 00 00 00
print(Mems.ptr(ofVal: &t))
t = .test2 //内存存的是1 0x00000001000106e0 01 00 00 00 00 00 00 00
t = .test3 //2 内存存的是2 0x00000001000106e0 02 00 00 00 00 00 00 00

print(MemoryLayout<TestEnum>.size) //1
print(MemoryLayout<TestEnum>.stride) //1
print(MemoryLayout<TestEnum>.alignment) //1

1.2 原始值case的情况




var t = TestEnum.test1 //0x00000001000106c8  00 00 00 00 00 00 00 00
print(Mems.ptr(ofVal: &t))
t = .test2 //0x00000001000106c8  01 00 00 00 00 00 00 00
t = .test3 // 0x00000001000106c8  02 00 00 00 00 00 00 00

print(MemoryLayout<TestEnum>.size) //1
print(MemoryLayout<TestEnum>.stride) //1
print(MemoryLayout<TestEnum>.alignment) //1


结论原始值不影响枚举成员值的存储情况,和前面常规case还是一样的,原始值不占用枚举变量的内存

1.3 关联值的情况

enum TestEnum {
case test1(Int, Int, Int)
case test2(Int, Int)
case test3(Int)
case test4(Bool)
case test5
}
var e = TestEnum.test1(1, 2, 3)
e = .test2(4, 5)
e = .test3(6)
e = .test4(true)
e = .test5


现象
    enum TestEnum {
        case test1(Int, Int, Int)
        case test2(Int, Int)
        case test3(Int)
        case test4(Bool)
        case test5
    }
    
    // 1个字节存储成员值
    // N个字节存储关联值(N取占用内存最大的关联值),任何一个case的关联值都共用这N个字节
    // 共用体
    
    // 小端:高高低低
    // 01 00 00 00 00 00 00 00
    // 02 00 00 00 00 00 00 00
    // 03 00 00 00 00 00 00 00
    // 00 枚举成员值
    // 00 00 00 00 00 00 00
    var e = TestEnum.test1(1, 2, 3)
    print(Mems.ptr(ofVal: &e))
    
    // 04 00 00 00 00 00 00 00
    // 05 00 00 00 00 00 00 00
    // 00 00 00 00 00 00 00 00
    // 01 枚举成员值
    // 00 00 00 00 00 00 00
    e = .test2(4, 5)
    print(Mems.memStr(ofVal: &e))
    
    // 06 00 00 00 00 00 00 00
    // 00 00 00 00 00 00 00 00
    // 00 00 00 00 00 00 00 00
    // 02 枚举成员值
    // 00 00 00 00 00 00 00
    e = .test3(6)
    
    // 01 00 00 00 00 00 00 00
    // 00 00 00 00 00 00 00 00
    // 00 00 00 00 00 00 00 00
    // 03 枚举成员值
    // 00 00 00 00 00 00 00
    e = .test4(true)
    
    // 00 00 00 00 00 00 00 00
    // 00 00 00 00 00 00 00 00
    // 00 00 00 00 00 00 00 00
    // 04
    // 00 00 00 00 00 00 00
    e = .test5
    print(MemoryLayout<TestEnum>.size) //25
    print(MemoryLayout<TestEnum>.stride) //32
    print(MemoryLayout<TestEnum>.alignment) //8



结论:
 // 1个字节存储成员值
 // N个字节存储关联值(N取占用内存最大的关联值),任何一个case的关联值都共用这N个字节
    

1.4  只有一个case的情况

enum TestEnum {
   case test1
}


print(MemoryLayout<TestEnum>.size) //0
print(MemoryLayout<TestEnum>.stride) //1
print(MemoryLayout<TestEnum>.alignment) //1

1.5 一个case的关联值

enum TestEnum {
case test(Int)
}
var t = TestEnum.test(10)

print(MemoryLayout<TestEnum>.size) //8
print(MemoryLayout<TestEnum>.stride) //8
print(MemoryLayout<TestEnum>.alignment) //8

因为只有一个case 只需要花8个字节来存你的关联值就行

综上 存储成员值的情况前提是有多个case,如果只有一个case的情况就没必要再花一个字节的内存去存成员值

二、switch底层原理

大概原理 取出那个成员值,然后拿成员值和case里面的值进行比较,和case 里面的哪个值相同就跳转到相应的位置

三、汇编

3.1 程序的本质

3.2 寄存器与内存 的关系

 var a = 3

var b = a + 1  这句代码要经过如下操作

为什么不直接在内存中移动,cpu 他支持的指令他是有限制的

第一个限定 他是不支持数据内存挪内存的,如果你想把一个内存的数据挪动到宁一个内存,必须要经过寄存器,这是规定;

第二个 如果你想进行一些运算,必须将数据拉到cpu里面,运算完再送回去

3.3  编程语言的发展

3.4 汇编语言的种类

3.5  常见汇编指令

(这里面装的是内存地址)%rbp寄存器里面存的内存地址值- 0x18

movq   -0x18(%rbp), %rax

movq根据这个内存地址对应的存贮空间的数据取出来赋值%rax

leaq  -0x18(%rbp), %rax

leaq根据这个内存地址赋值%rax

获取地址和对应地址的内存数据

//
//  MemsTest.swift
//  TestSwift
//
//  Created by lxj on 2025/3/2.
//  Copyright © 2025 lxj
//


import Foundation

public enum MemAlign : Int {
    case one = 1, two = 2, four = 4, eight = 8
}

private let _EMPTY_PTR = UnsafeRawPointer(bitPattern: 0x1)!

/// 辅助查看内存的小工具类
public struct Mems<T> {
    private static func _memStr(_ ptr: UnsafeRawPointer,
                                _ size: Int,
                                _ aligment: Int) ->String {
        if ptr == _EMPTY_PTR { return "" }
        
        var rawPtr = ptr
        var string = ""
        let fmt = "0x%0\(aligment << 1)lx"
        let count = size / aligment
        for i in 0..<count {
            if i > 0 {
                string.append(" ")
                rawPtr += aligment
            }
            let value: CVarArg
            switch aligment {
            case MemAlign.eight.rawValue:
                value = rawPtr.load(as: UInt64.self)
            case MemAlign.four.rawValue:
                value = rawPtr.load(as: UInt32.self)
            case MemAlign.two.rawValue:
                value = rawPtr.load(as: UInt16.self)
            default:
                value = rawPtr.load(as: UInt8.self)
            }
            string.append(String(format: fmt, value))
        }
        return string
    }
    
    private static func _memBytes(_ ptr: UnsafeRawPointer,
                                  _ size: Int) -> [UInt8] {
        var arr: [UInt8] = []
        if ptr == _EMPTY_PTR { return arr }
        for i in 0..<size {
            arr.append((ptr + i).load(as: UInt8.self))
        }
        return arr
    }
    
    /// 获得变量的内存数据(字节数组格式)
    public static func memBytes(ofVal v: inout T) -> [UInt8] {
        return _memBytes(ptr(ofVal: &v), MemoryLayout.stride(ofValue: v))
    }
    
    /// 获得引用所指向的内存数据(字节数组格式)
    public static func memBytes(ofRef v: T) -> [UInt8] {
        let p = ptr(ofRef: v)
        return _memBytes(p, malloc_size(p))
    }
    
    /// 获得变量的内存数据(字符串格式)
    ///
    /// - Parameter alignment: 决定了多少个字节为一组
    public static func memStr(ofVal v: inout T, alignment: MemAlign? = nil) -> String {
        let p = ptr(ofVal: &v)
        return _memStr(p, MemoryLayout.stride(ofValue: v),
                       alignment != nil ? alignment!.rawValue : MemoryLayout.alignment(ofValue: v))
    }
    
    /// 获得引用所指向的内存数据(字符串格式)
    ///
    /// - Parameter alignment: 决定了多少个字节为一组
    public static func memStr(ofRef v: T, alignment: MemAlign? = nil) -> String {
        let p = ptr(ofRef: v)
        return _memStr(p, malloc_size(p),
                       alignment != nil ? alignment!.rawValue : MemoryLayout.alignment(ofValue: v))
    }
    
    /// 获得变量的内存地址
    public static func ptr(ofVal v: inout T) -> UnsafeRawPointer {
        return MemoryLayout.size(ofValue: v) == 0 ? _EMPTY_PTR : withUnsafePointer(to: &v) {
            UnsafeRawPointer($0)
        }
    }
    
    /// 获得引用所指向内存的地址
    public static func ptr(ofRef v: T) -> UnsafeRawPointer {
        if v is Array<Any>
            || Swift.type(of: v) is AnyClass
            || v is AnyClass {
            return UnsafeRawPointer(bitPattern: unsafeBitCast(v, to: UInt.self))!
        } else if v is String {
            var mstr = v as! String
            if mstr.memType() != .heap {
                return _EMPTY_PTR
            }
            return UnsafeRawPointer(bitPattern: unsafeBitCast(v, to: (UInt, UInt).self).1)!
        } else {
            return _EMPTY_PTR
        }
    }
    
    /// 获得变量所占用的内存大小
    public static func size(ofVal v: inout T) -> Int {
        return MemoryLayout.size(ofValue: v) > 0 ? MemoryLayout.stride(ofValue: v) : 0
    }
    
    /// 获得引用所指向内存的大小
    public static func size(ofRef v: T) -> Int {
        return malloc_size(ptr(ofRef: v))
    }
}

public enum StringMemType : UInt8 {
    /// TEXT段(常量区)
    case text = 0xd0
    /// taggerPointer
    case tagPtr = 0xe0
    /// 堆空间
    case heap = 0xf0
    /// 未知
    case unknow = 0xff
}

extension String {
    mutating public func memType() -> StringMemType {
        let ptr = Mems.ptr(ofVal: &self)
        return StringMemType(rawValue: (ptr + 15).load(as: UInt8.self) & 0xf0)
            ?? StringMemType(rawValue: (ptr + 7).load(as: UInt8.self) & 0xf0)
            ?? .unknow
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Anolis服务器Arm64架构服务器配置(其他版本服务器解决方式思路一质)

Anolis服务器Arm64架构服务器配置 1.nginx配置1.1.尝试安装nginx1.2.资源准备1.2.1.查看服务器系统版本:1.2.2.下载依赖包:1.3.正式安装nginx1.3.1.下载nginx并上传服务器1.3.2.开始安装nginx1.4.防火墙配置1.4.1.直接关闭防火墙:不推荐,但省事1.4.2.命令介绍1.4.3.配置开启…

threejs:着色器onBeforeCompile给导入的模型添加光带扫描效果

模型材质属性丢失 上一篇博客我们学习了用着色器给模型添加光带扫描效果&#xff0c;今天来学习给导入的模型添加光带扫描效果&#xff0c;目标是给如下图的立筒仓加光带扫描。 首先我们试试原来的方法还是否有效。 import * as THREE from three;// 引入gltf模型加载库GLTFL…

MySQL零基础教程16—表连接进阶

复习表别名 之前已经学习过&#xff0c;查询的时候可以使用as来对检索的列进行重命名&#xff0c;这样可以让sql更加简介&#xff0c;增强易读性&#xff08;as可以省略&#xff09; 此外&#xff0c;使用表别名还可以支持在一条select语句中&#xff0c;一个表是被多次使用 …

K8s控制器Deployment详解

回顾 ReplicaSet 控制器,该控制器是用来维护集群中运行的 Pod 数量的&#xff0c;但是往往在实际操作的时候&#xff0c;我们反而不会去直接使用 RS&#xff0c;而是会使用更上层的控制器&#xff0c;比如说 Deployment。 Deployment 一个非常重要的功能就是实现了 Pod 的滚动…

rabbitmq-amqp事务消息+消费失败重试机制+prefetch限流

1. 安装和配置 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency><dependency> <groupId>com.fasterxml.jackson.core</groupId> <arti…

探秘基带算法:从原理到5G时代的通信变革【八】QAM 调制 / 解调

文章目录 2.7 QAM 调制 / 解调2.7.1 概述2.7.2 星座图星座图的结构与性能发射端的信息编码与接收端的解码差分编码的分类与实现差分编码的模4格雷加法器公式16QAM星座图与映射关系 2.7.3 信号表达式正交振幅调制的基本原理与系统分析相位误差对QAM性能的影响多电平正交振幅调制…

idea生成自定义Maven原型(archetype)项目工程模板

一、什么是Maven原型&#xff08;Maven archetype&#xff09; 引自官网的介绍如下&#xff1a; Maven原型插件官网地址 这里采用DeepSeek助手翻译如下&#xff1a; Maven 原型 什么是原型&#xff1f; 简而言之&#xff0c;原型是一个 Maven 项目模板工具包。原型被定义为一…

决策树(Decision Tree)基础知识

目录 一、回忆1、*机器学习的三要素&#xff1a;1&#xff09;*函数族2&#xff09;*目标函数2.1&#xff09;*模型的其他复杂度参数 3&#xff09;*优化算法 2、*前处理/后处理1&#xff09;前处理&#xff1a;特征工程2&#xff09;后处理&#xff1a;模型选择和模型评估 3、…

Python学习(十四)pandas库入门手册

目录 一、安装与导入二、核心数据结构2.1 Series 类型&#xff08;一维数组&#xff09;2.2 DataFrame 类型&#xff08;二维数组&#xff09; 三、数据读取与写入3.1 读取 CSV 和 Excel 文件3.2 写入数据 四、数据清洗与处理4.1 处理缺失值4.2 数据筛选4.3 数据排序 五、数据分…

通过计费集成和警报监控 Elasticsearch Service 成本

作者&#xff1a;来自 Elastic Alexis Charveriat 使用 Elasticsearch 服务计费集成来跟踪、定制和提醒 Elasticsearch 服务费用。 监控和管理你的Elasticsearch服务&#xff08;ESS&#xff09;使用情况和成本对高效运营至关重要。 Elasticsearch服务计费集成提供了一种简化的…

cmake、CMakeLists.txt、make、ninja

文章目录 一、概念0.cmake官网1.什么是cmake2.为什么使用cmake3.CMakeLists.txt 二、CMakeLists.txt语法&#xff1a;如何编写CMakeLists.txt&#xff0c;语法详解(0)语法基本原则(1)project关键字(2)set关键字(3)message关键字(4)add_executable关键字(5)add_subdirectory关键…

DeepSeek本地接口调用(Ollama)

前言 上篇博文&#xff0c;我们通过Ollama搭建了本地的DeepSeek模型&#xff0c;本文主要是方便开发人员&#xff0c;如何通过代码或工具&#xff0c;通过API接口调用本地deepSeek模型 前文&#xff1a;DeepSeek-R1本地搭建_deepseek 本地部署-CSDN博客 注&#xff1a;本文不仅…

前端基础之浏览器本地存储

如我们在一些网站中&#xff0c;去进行数据搜索&#xff0c;在浏览器中是有一个对于的存储的&#xff0c;并且我们可以去手动进行value的增删操作 LocalStroage的使用 并且将浏览器关闭之后&#xff0c;数据也会保存&#xff0c;除非用户手动清理数据或是清空缓存 <!DOCTYPE…

2025 聚合易支付完整版PHP网站源码

源码介绍 2025 聚合易支付完整版PHP网站源码 PHP版本&#xff1a;PHP74 源码上传服务器&#xff0c;解压访问域名即可安装 安装完成后一定要设置伪静态 源码里面nginx.txt 就是伪静态 然后复制粘贴到伪静态里面保存即可 部分截图 源码获取 2025 聚合易支付完整版PHP网站源码…

Spring Boot 3 整合 MinIO 实现分布式文件存储

引言 文件存储已成为一个做任何应用都不可回避的需求。传统的单机文件存储方案在面对大规模数据和高并发访问时往往力不从心&#xff0c;而分布式文件存储系统则提供了更好的解决方案。本篇文章我将基于Spring Boot 3 为大家讲解如何基于MinIO来实现分布式文件存储。 分布式存…

easyExcel使用案例有代码

easyExcel 入门,完成web的excel文件创建和导出 easyExcel官网 EasyExcel 的主要特点如下&#xff1a; 1、高性能&#xff1a;EasyExcel 采用了异步导入导出的方式&#xff0c;并且底层使用 NIO 技术实现&#xff0c;使得其在导入导出大数据量时的性能非常高效。 2、易于使…

NVIDIA(英伟达) GPU 芯片架构发展史

GPU 性能的关键参数 CUDA 核心数量&#xff08;个&#xff09;&#xff1a;决定了 GPU 并行处理能力&#xff0c;在 AI 等并行计算类业务下&#xff0c;CUDA 核心越多性能越好。 显存容量&#xff08;GB&#xff09;&#xff1a;决定了 GPU 加载数据量的大小&#xff0c;在 AI…

FFMPEG利用H264+AAC合成TS文件

本次的DEMO是利用FFMPEG框架把H264文件和AAC文件合并成一个TS文件。这个DEMO很重要&#xff0c;因为在后面的推流项目中用到了这方面的技术。所以&#xff0c;大家最好把这个项目好好了解。 下面这个是流程图 从这个图我们能看出来&#xff0c;在main函数中我们主要做了这几步&…

获取Kernel32基地址

暴力搜索 32位在4G内存搜索有一定可行性&#xff0c;但是处理起来其实还是比较麻烦的&#xff0c;因为内存不可读会触发异常&#xff0c;需要对这些异常问题进行处理。 优化思路:缩小范围、增大搜索步长 (1)不优化&#xff0c;原始内存特征匹配&#xff0c;容易出错&#xf…

【 <一> 炼丹初探:JavaWeb 的起源与基础】之 Servlet 与 JSP 的协作:MVC 模式的雏形

<前文回顾> 点击此处查看 合集 https://blog.csdn.net/foyodesigner/category_12907601.html?fromshareblogcolumn&sharetypeblogcolumn&sharerId12907601&sharereferPC&sharesourceFoyoDesigner&sharefromfrom_link <今日更新> 一、Servl…