原因当然是由于编译器优化,正如评论中已经指出的那样。
记住 Objective-C 是建立在 C 之上的,我整理了一个具有不同优化级别的简单 C 示例,这就是结果。
原始代码
int main(int argc, char const *argv[]) {
char _isReadyForData = 0;
while (!_isReadyForData);
return 0;
}
没有优化的 LLVM IR (-O0)
define i32 @main(i32 %argc, i8** %argv) #0 {
entry:
%retval = alloca i32, align 4
%argc.addr = alloca i32, align 4
%argv.addr = alloca i8**, align 8
%_isReadyForData = alloca i8, align 1
store i32 0, i32* %retval
store i32 %argc, i32* %argc.addr, align 4
store i8** %argv, i8*** %argv.addr, align 8
store i8 0, i8* %_isReadyForData, align 1
br label %while.cond
while.cond: ; preds = %while.body, %entry
%0 = load i8* %_isReadyForData, align 1
%tobool = icmp ne i8 %0, 0
%lnot = xor i1 %tobool, true
br i1 %lnot, label %while.body, label %while.end
while.body: ; preds = %while.cond
br label %while.cond
while.end: ; preds = %while.cond
ret i32 0
}
具有 1 级优化的 LLVM IR (-O1)
define i32 @main(i32 %argc, i8** nocapture %argv) #0 {
entry:
br label %while.cond
while.cond: ; preds = %while.cond, %entry
br label %while.cond
}
如您所见,编译器在优化时会产生一个无限循环,因为局部变量_isReadyForData
在该上下文中是无用的,因此被删除。
正如@faffaffaff 所建议的,使用volatile
关键字 on_isReadyForData
可以解决问题。
具有 1 级优化 (-O1) 和 volatile 关键字的 LLVM IR
define i32 @main(i32 %argc, i8** nocapture %argv) #0 {
entry:
%_isReadyForData = alloca i8, align 1
store volatile i8 0, i8* %_isReadyForData, align 1
br label %while.cond
while.cond: ; preds = %while.cond, %entry
%_isReadyForData.0.load1 = load volatile i8* %_isReadyForData, align 1
%lnot = icmp eq i8 %_isReadyForData.0.load1, 0
br i1 %lnot, label %while.cond, label %while.end
while.end: ; preds = %while.cond
ret i32 0
}
但我绝对同意@rmaddy 的说法,即您最好更改程序流程并使用驱动逻辑,而不是修补已有的内容。