zoukankan      html  css  js  c++  java
  • block 解析

    block变量

    上一篇 讲的是block静态变量的特性,这里我们来看一下_block变量。引用官方:

    You can specify that an imported variable be mutable—that is, read-write— by applying the __block storage type modifier. __blockstorage is similar to, but mutually exclusive of, the registerauto, and static storage types for local variables.

    通过指定__block存储类型修饰符,可以读写。__block存储是类似的,但相互排斥的,寄存器,自动变量,和局部变量和静态变量类型(后面这句不太理解)。 
    我们来写个例子,用__block修饰局部变量(对于全局变量是无效的,没有任何作用,全局变量成员变量本身就可以在block内部修改,详细看这一篇
    void main1()
    {
        __block char *_para1="a";
        printf("init _para1:%s,%p,%p
    ",_para1,_para1,&_para1);
        void(^testBlock)(void)=^{
            printf("exute _para1:%s,%p,%p
    ",_para1,_para1,&_para1);
        };
        _para1="b";
        printf("before _para1:%s,%p,%p
    ",_para1,_para1,&_para1);
        testBlock();
        printf("after _para1:%s,%p,%p
    ",_para1,_para1,&_para1);
    }
    执行后输出如下:
    init _para1:a,0x47f4,0xbfffc9c0
    before _para1:b,0x4829,0x8da4580
    exute _para1:b,0x4829,0x8da4580
    after _para1:b,0x4829,0x8da4580

    这里加了__block修饰符。通过日志可以看出,block内部_para1的地址、值和执行前的_para1一样,在block初始化后,对变量_para1的修改,可以同步到block内,block内并不是截获了变量的值。我们可以看下通过clang 转换后的后的cpp代码:

    //block 的实现函数的对象
    struct __block_impl {
      void *isa;
      int Flags;
      int Reserved;
      void *FuncPtr;
    };
    //block 引用的参数对象(每一个参数生成一个结构体)
    struct __Block_byref__para1_0 {
      void *__isa;
    __Block_byref__para1_0 *__forwarding;
     int __flags;
     int __size;
     char *_para1;
    };
    //block对象
    struct __main1_block_impl_0 {
      struct __block_impl impl;
      struct __main1_block_desc_0* Desc;
      __Block_byref__para1_0 *_para1; // by ref
      __main1_block_impl_0(void *fp, struct __main1_block_desc_0 *desc, __Block_byref__para1_0 *__para1, int flags=0) : _para1(__para1->__forwarding) {
        impl.isa = &_NSConcreteStackBlock;
        impl.Flags = flags;
        impl.FuncPtr = fp;
        Desc = desc;
      }
    };
    //block 的实现
    static void __main1_block_func_0(struct __main1_block_impl_0 *__cself) {
      __Block_byref__para1_0 *_para1 = __cself->_para1; // bound by ref
    
            printf("exute _para1:%s,%p,%p
    ",(_para1->__forwarding->_para1),(_para1->__forwarding->_para1),&(_para1->__forwarding->_para1));
        }
    //其他函数(copy、dispose:为了管理_Block_byref__para1_0 结构体变量的内存)
    static void __main1_block_copy_0(struct __main1_block_impl_0*dst, struct __main1_block_impl_0*src) {_Block_object_assign((void*)&dst->_para1, (void*)src->_para1, 8/*BLOCK_FIELD_IS_BYREF*/);}
    
    static void __main1_block_dispose_0(struct __main1_block_impl_0*src) {_Block_object_dispose((void*)src->_para1, 8/*BLOCK_FIELD_IS_BYREF*/);}
    
    static struct __main1_block_desc_0 {
      size_t reserved;
      size_t Block_size;
      void (*copy)(struct __main1_block_impl_0*, struct __main1_block_impl_0*);
      void (*dispose)(struct __main1_block_impl_0*);
    } __main1_block_desc_0_DATA = { 0, sizeof(struct __main1_block_impl_0), __main1_block_copy_0, __main1_block_dispose_0};
    //这是我们的测试函数
    void main1()
    {
        __attribute__((__blocks__(byref))) __Block_byref__para1_0 _para1 = {(void*)0,(__Block_byref__para1_0 *)&_para1, 0, sizeof(__Block_byref__para1_0), "a"};
        printf("init _para1:%s,%p,%p
    ",(_para1.__forwarding->_para1),(_para1.__forwarding->_para1),&(_para1.__forwarding->_para1));
        void(*testBlock)(void)=(void (*)())&__main1_block_impl_0((void *)__main1_block_func_0, &__main1_block_desc_0_DATA, (__Block_byref__para1_0 *)&_para1, 570425344);
        (_para1.__forwarding->_para1)="b";
        printf("before _para1:%s,%p,%p
    ",(_para1.__forwarding->_para1),(_para1.__forwarding->_para1),&(_para1.__forwarding->_para1));
        ((void (*)(__block_impl *))((__block_impl *)testBlock)->FuncPtr)((__block_impl *)testBlock);
        printf("after _para1:%s,%p,%p
    ",(_para1.__forwarding->_para1),(_para1.__forwarding->_para1),&(_para1.__forwarding->_para1));
    }
    
    

    发现和不加__block不太一样,多了一个结构体(_Block_byref__para1_0)

    
    
    struct __Block_byref__para1_0 {
      void *__isa;
    __Block_byref__para1_0 *__forwarding;
     int __flags;
     int __size;
     char *_para1;
    };
    
    

    这个结构体就是用__block 声明的变量,声明__block变量_para1 转换后的代码如下:

    __attribute__((__blocks__(byref))) __Block_byref__para1_0 _para1 = {(void*)0,(__Block_byref__para1_0 *)&_para1, 0, sizeof(__Block_byref__para1_0), "a"};

    其实就是生成一个_Block_byref__para1_0对象,__forwarding 指针指向变量结构体自己

    void(*testBlock)(void)=(void (*)())&__main1_block_impl_0((void *)__main1_block_func_0, &__main1_block_desc_0_DATA, (__Block_byref__para1_0 *)&_para1, 570425344);

    初始化block,传递结构体变量_para1、函数地址、描述信息等参数,block对象的成员 _para1 引用了_para1结构体的地址,这样就可以修改_para1,而且外界对_para1结构体的修改都可以同步到block对象的成员_para1中,修改代码如下:

    (_para1.__forwarding->_para1)="b";

    直接通过__Block_byref__para1_0 结构体的成员__forwarding(指向自己)取得_para1成员的地址,然后就可以读写,达到了修改变量的目的。

    ((void (*)(__block_impl *))((__block_impl *)testBlock)->FuncPtr)((__block_impl *)testBlock);

    执行block,依然是通过调用函数指针 FuncPtr 实现,并传递block自身。函数体代码如下:

    static void __main1_block_func_0(struct __main1_block_impl_0 *__cself) {
      __Block_byref__para1_0 *_para1 = __cself->_para1; // bound by ref
    
            printf("exute _para1:%s,%p,%p
    ",(_para1->__forwarding->_para1),(_para1->__forwarding->_para1),&(_para1->__forwarding->_para1));
        }

    在函数体内,通过block对象的成员_para1(__Block_byref__para1_0的指针,再通过自身的成员__forwarding指针来获取_para1。

    我的理解就是指针引用的关系,不知道为什么要加一个__forwarding指针 ,直接去引用自身的成员 _para1难道不行吗?希望大神赐教。

  • 相关阅读:
    2020年9月29日
    随机生成验证码
    动手动脑java语法基础
    Java语法之动手实验
    代码大全2 读书笔记
    java动手动动脑之字串联接
    二柱子问题
    生成随机四则运算1
    可变参数
    2020年9月30日
  • 原文地址:https://www.cnblogs.com/NarutoYq/p/3873194.html
Copyright © 2011-2022 走看看