Why is this block not global?

三世轮回 提交于 2019-12-12 11:18:35

问题


Consider the following code:

#include <stdio.h>

typedef void (^block)();

block foo() {
  char a = 'a';
  return [^{
    printf("%c\n", a);
  } copy];
}

block bar() {
  const char a = 'a';
  return [^{
    printf("%c\n", a);
  } copy];
}

This is what that compiles to for armv7:

_foo:
@ BB#0:
        push    {r7, lr}
        mov     r7, sp
        sub     sp, #24
        movw    r3, :lower16:(L__NSConcreteStackBlock$non_lazy_ptr-(LPC0_0+4))
        movt    r3, :upper16:(L__NSConcreteStackBlock$non_lazy_ptr-(LPC0_0+4))
        movw    r1, :lower16:(___foo_block_invoke_0-(LPC0_1+4))
LPC0_0:
        add     r3, pc
        movt    r1, :upper16:(___foo_block_invoke_0-(LPC0_1+4))
        movw    r0, :lower16:(L_OBJC_SELECTOR_REFERENCES_-(LPC0_2+4))
LPC0_1:
        add     r1, pc
        movt    r0, :upper16:(L_OBJC_SELECTOR_REFERENCES_-(LPC0_2+4))
        movw    r2, :lower16:(___block_descriptor_tmp-(LPC0_3+4))
        ldr     r3, [r3]
        movt    r2, :upper16:(___block_descriptor_tmp-(LPC0_3+4))
        str     r3, [sp]
        mov.w   r3, #1073741824
LPC0_2:
        add     r0, pc
        str     r3, [sp, #4]
        movs    r3, #0
LPC0_3:
        add     r2, pc
        str     r3, [sp, #8]
        str     r1, [sp, #12]
        ldr     r1, [r0]
        mov     r0, sp
        str     r2, [sp, #16]
        movs    r2, #97
        strb.w  r2, [sp, #20]
        blx     _objc_msgSend
        add     sp, #24
        pop     {r7, pc}

_bar:
@ BB#0:
        movw    r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_-(LPC2_0+4))
        movt    r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_-(LPC2_0+4))
        movw    r0, :lower16:(___block_literal_global-(LPC2_1+4))
LPC2_0:
        add     r1, pc
        movt    r0, :upper16:(___block_literal_global-(LPC2_1+4))
LPC2_1:
        add     r0, pc
        ldr     r1, [r1]
        b.w     _objc_msgSend

What confuses me is the first block is not a global block. It's a stack block and then copied. That doesn't make sense to me. Is it something I'm overlooking in the C-standard for why the compiler can't automatically infer that a can actually be considered const?

I'm building this Os, ARC enabled, and here's my clang version:

$ clang -v
Apple clang version 4.1 (tags/Apple/clang-421.11.66) (based on LLVM 3.1svn)
Target: x86_64-apple-darwin12.4.0
Thread model: posix

回答1:


The declaration char a requires storage, and this means that the block in foo requires its own variable a which is initialised to the value of foo's a. The block's variable is stored in it's "environment".

The declaration const char a does not require storage to be allocated unless the address of a is taken (by the C Language Specification). Any use of a's value can be replaced directly by its constant value. This means that bar can be compiled without any environment.

So the two blocks are compiled differently.

In theory a compiler, if the language specification doesn't disallow it, might be able examine the declaration and use of a variable, determine that it is not externally visible, determine its value never changes after initial assignment and that its address is never taken, and then replace the variable by a constant value... but that's a lot of analysis for probably a small, if any, payoff.



来源:https://stackoverflow.com/questions/17957319/why-is-this-block-not-global

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!