我的问题是:为啥仅在使用x86_64编译时会出现此编译错误?以及如何解决?
我的问题是:为什么只有当选择x86_64模拟器编译错误时才会发生?以及如何解决?
环境:Xcode v8.3.2
测试代码:
+ (BOOL)updateSqlByFileName:(NSString *)file key:(NSString *)key, ...
{
va_list args;
va_start(args, key);
__block BOOL isOK = NO;
[_queue inDatabase:^(FMDatabase *_dataBase)//
{
isOK = [_dataBase executeUpdate:sql withVAList:args];
}];
va_end(args);
return isOK;
}
的不同的编译方式,编译错误情况:
【编译正常√】选择通用iOS设备编译(构建)时:【armv7 + arm64】
CompileC Test.m normal armv7 objective-c com.apple.compilers.llvm.clang.1_0.compiler
CompileC Test.m normal arm64 objective-c com.apple.compilers.llvm.clang.1_0.compiler
【编译正常√】选择真机:iPhone 4(7.1.2)编译(Build)时:【armv7】
CompileC Test.m normal armv7 objective-c com.apple.compilers.llvm.clang.1_0.compiler
【编译错误×】选择模拟器:iPhone 5s(10.3),iPhone SE(10.3),iPhone 7 Plus(10.3)编译(Build)时:【x86_64】
CompileC Test.m normal x86_64 objective-c com.apple.compilers.llvm.clang.1_0.compiler
编译错误:
中引用带有数组类型的声明
无法在块
【编译正常√】选择模拟器:iPhone 5(10.3)编译(Build)时:【i386】
CompileC Test.m normal i386 objective-c com.apple.compilers.llvm.clang.1_0.compiler
答案 0 :(得分:2)
如果块捕获非__block
变量,则在创建块并将其存储在块中时,会生成变量的副本。无法在C中分配数组,这可能就是为什么块的设计者不允许在块中捕获数组类型的变量。
C标准未指定哪种类型va_list
;它是特定于实现的。它可以实现为数组类型,指针类型,结构类型等等,并且这可以在同一编译器上的体系结构之间有所不同。可能他们在x86_64中将其实现为数组类型,在其他3种体系结构中实现为某些非数组类型。这没什么不寻常的。您无法假设va_list
类型是什么类型。
在您定义另一个函数并将va_list
传递给它的答案中,这恰好适用于va_list
是数组类型的情况,因为C会自动调整“数组”类型的任何参数T“to”指向T“的指针,因此当args
是数组类型时,方法+foo:key:withVAList:
中的参数va_list
实际上具有指针类型(与{{1}不同的类型在args
方法中),指针变量可以被捕获到一个块中。
另一种解决方案是获取+foo:key:
的地址,获取va_list
并将其放入块中使用的变量中。无论va_list *
是什么,这都保证是指针类型,并且可以在块中捕获。当您需要使用块内的实际va_list
时,您可以取消引用指针。例如,像这样:
va_list
答案 1 :(得分:-2)
+ (BOOL)foo:(NSString *)file key:(NSString *)key, ...
{
va_list args;
va_start(args, key);
BOOL isOK = [self foo:file key:key withVAList:args];
va_end(args);
return isOK;
}
+ (BOOL)foo:(NSString *)file key:(NSString *)key withVAList:(va_list)args
{
__block BOOL isOK = NO;
[_queue inDatabase:^(FMDatabase *_dataBase){
isOK = [_dataBase executeUpdate:sql withVAList:args];
}];
return isOK;
}
参考代码(灵感来源):
FMDB类库里的executeQuery函数
- (FMResultSet *)executeQuery:(NSString*)sql, ... {
va_list args;
va_start(args, sql);
id result = [self executeQuery:sql withArgumentsInArray:nil orDictionary:nil orVAList:args];
va_end(args);
return result;
}
- (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray*)arrayArgs orDictionary:(NSDictionary *)dictionaryArgs orVAList:(va_list)args {
//xxx
}