4

考虑以下代码:

#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];
}

这是为 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

让我困惑的是第一个块不是全局块。它是一个堆栈块,然后被复制。这对我来说没有意义。我在 C 标准中忽略了为什么编译器不能自动推断出a实际上可以考虑的东西const吗?

我正在构建这个Os,启用了 ARC,这是我的 clang 版本:

$ 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
4

1 回答 1

1

声明char a需要存储,这意味着 in 块foo需要自己的变量,该变量a被初始化为' s的。块的变量存储在它的“环境”中。fooa

该声明const char a不需要分配存储空间,除非获取地址a(通过 C 语言规范)。' 值的任何使用a都可以直接替换为其常量值。这意味着bar可以在没有任何环境的情况下进行编译。

所以这两个块的编译方式不同。

理论上,如果语言规范不允许,编译器可能会检查变量的声明和使用,确定它在外部不可见,确定它的值在初始赋值后永远不会改变,并且它的地址永远不会被占用,然后用一个常数值替换变量......但这可能是一个很小的分析,如果有的话。

于 2013-07-30T22:33:17.270 回答