• Block中为什么无法引用c语言数组


    更新记录

    时间 版本修改
    2020年4月12日 初版

    Block引用C语言数组报错

    char text[] = "hello";
    void (^blk)(void) = ^{
            printf("%c
    ",text[2]);
    };
    
    • 报编译错误:error:cannot refer to declaration with an array type inside block
    • 《Objective-C 高级编程 iOS与OS X多线程和内存管理》2.3.1 Block的实质中,提出解决方案,修改成如下代码:
    char text[] = "hello";
    int main(int argc, const char * argv[]) {
       void (^blk)(void) = ^{
            printf("%c
    ",text[2]);
        };
        return 0;
    }
    

    报错的根本原因

    struct __main_block_impl_0 {
      struct __block_impl impl;
      struct __main_block_desc_0* Desc;
      const char *fmt;
      int val;              //block捕获的变量 val
      __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, const char *_fmt, int _val, int flags=0) : fmt(_fmt), val(_val) {
        impl.isa = &_NSConcreteStackBlock;
        impl.Flags = flags;
        impl.FuncPtr = fp;
        Desc = desc;
      }
    };
    
    • 上述的block,捕获了一个const char*和一个int。所以构造函数中会多两个参数。
    • 上述就是目前编译器的实现,所以如果捕获一个C语言数组,会变成如下代码:
    struct __main_block_impl_0 {
      struct __block_impl impl;
      struct __main_block_desc_0* Desc;
      const char *fmt;
      int val;              //block捕获的变量 val
      char szArray[10];
      __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, const char *_fmt, int _val, char _szArray[10], int flags=0) : fmt(_fmt), val(_val), szArray[10](_szArray) {
        impl.isa = &_NSConcreteStackBlock;
        impl.Flags = flags;
        impl.FuncPtr = fp;
        Desc = desc;
      }
    };
    
    • 由于转换成了构造函数的参数列表的形式,实质上就是调用了szArray[10] = _szArray这样的语句。虽然变量的类型以及数组的大小都相同,但C语言规范不允许这种赋值。因此会报编译错误。

    捕获指针替代捕获C语言数组

    • 上述可以正常编译的代码,实际对应的转换后的C/C++源代码如下:
    struct __block_impl {
        void *isa;
        int Flags;
        int Reserved;
        void *FuncPtr;
    };
    struct __main_block_impl_0 {
        struct __block_impl impl;
        struct __main_block_desc_0* Desc;
        char *text;
        __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, char *_text, int flags=0) : text(_text) {
            impl.isa = &_NSConcreteStackBlock;
            impl.Flags = flags;
            impl.FuncPtr = fp;
            Desc = desc;
        }
    };
    static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
        char *text = __cself->text; // bound by copy
    
        printf("%c
    ",text[2]);
        
    }
    
    static struct __main_block_desc_0 {
        size_t reserved;
        size_t Block_size;
    } __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};
    
    int main(int argc, const char * argv[]) {
        char text[] = "hello";
        __main_block_impl_0 block_struct = __main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, text);
        void (*blk)() = (void (*)())&block_struct;
        ((void (*)(__block_impl *))((__block_impl *)blk)->FuncPtr)((__block_impl *)blk);
        return 0;
    }
    
    • 因为对于指针的赋值text = _text是符合C语言语法规范的,因此这种用法是没有任何问题的。

    阅读延申

    char text[] = "hello";
    int main(int argc, const char * argv[]) {
       void (^blk)(void) = ^{
            printf("%c
    ",text[2]);
        };
        return 0;
    }
    
    • 但是,它的原因是因为:这个Block对象里面使用的是全局变量,它是不需要存储到自己的Block结构体中,即它的结构体应该是如下结构:
    struct __main_block_impl_0 {
        struct __block_impl impl;
        struct __main_block_desc_0* Desc;
    
        //如果block截获了自动变量,会放置在这里。由于该block内引用的是全局变量,并不会在此加入字段进行初始化。
    
        __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, char *_text, int flags=0) : text(_text) {
            impl.isa = &_NSConcreteStackBlock;
            impl.Flags = flags;
            impl.FuncPtr = fp;
            Desc = desc;
        }
    };
    
    • 虽然博文的结果具有参考性,但是需要特别区分好这两种做法的底层特性。

    参考资料

    • 《Objective-C 高级编程 iOS与OS X多线程和内存管理》2.3.1 Block的实质
    • 《Objective-C 高级编程 iOS与OS X多线程和内存管理》2.3.2 截获自动变量值
  • 相关阅读:
    【AtCoder】AtCoder Grand Contest 014 解题报告
    【CF603E】Pastoral Oddities(CDQ分治)
    【洛谷4654】[CEOI2017] Mousetrap(DP+二分)
    【洛谷4800】[CEOI2015 Day2] 核能国度(差分细节题)
    【CF626G】Raffles(贪心)
    【CF578E】Walking!(贪心)
    【AtCoder】AtCoder Grand Contest 015 解题报告
    【CF582E】Boolean Function(动态规划+FWT)
    【CF576E】Painting Edges(线段树分治+并查集)
    【CF576D】Flights for Regular Customers(矩乘套路题)
  • 原文地址:https://www.cnblogs.com/HelloGreen/p/12688875.html
Copyright © 2020-2023  润新知