苹果GNU C/C++,objective-C/C++新特性:Blocks
来源:互联网 发布:c语言 volatile 含义 编辑:程序博客网 时间:2024/05/16 05:16
而Apple现在 也引领了时尚,对XCode 3.2中的GCC 4.2扩充了Blocks新的语法特性,使其能够有助于多核应用的开发。
其中,Apple在 Snow Leopard中所用到的Grand Central Dispatch(GCD)就是基于Blocks实现的。关于Blocks以及GCD在苹果官方的介绍,请见:Introducing Blocks and Grand Central Dispatch。
下面先介绍一下编译器的设置,使其能够认得Blocks 语法。
首先,打开XCode3.2中菜单项Project中的Edit Project Settings。
在 Architectures大栏中的Base SDK项,我们要选择Mac OS X 10.6。
然后看Compiler Version这一栏,我们要将C/C++ Compiler Version项选择为GCC4.2。
最后,在GCC4.2 Language这一栏中,我们要找到C Language Dialect这一项,把它设为GNU99。
这样,编译环境的配制就完成了。
下面我们将开始介绍 Blocks
首先看一段最简单的例子:
- int main(void)
- {
- void (^blocks)(void) = ^(void){ puts("Hello, world!"); };
- blocks();
- }
首先,声明了一个变量void(^blocks)(void),表示一个指向void(void)的函数块的引用。而^(void){ puts("Hello, world!"); };则表示一个函数块,它接受void类型参数,并且返回void。其功能是输出Hello, world!。
下面的blocks();就是通过这个函数块的引用来调用函数。所以,这段代码的运行结果就是输出Hello, world!。
Blocks 比C++0x中的λ表达式更强的一点是,它可以是个数组类型:
- int main(void)
- {
- void (^p[2])(void) = { ^(void){ puts("Hello, world!"); }, ^(void){ puts("Goodbye!"); } };
- p[0](), p[1]();
- }
这 里p的类型为void(^[2])(void),表示含有2个void(^)(void)块引用元素的变量。
下面谈谈函数块对其外部临时 变量的可访问情况。
- static int global = 100;
- int main(void)
- {
- int local = 200;
- void (^p)(void) = ^(void){ printf("The answer is: %dn", global + local); };
- p();
- }
对 于FP比较熟悉的朋友可能会想到,如果一个外部变量能够随随便便被一个函数块修改的话,那么对于其本身的副作用仍然无法进行方便地多核并行编程。
那 么我们不妨试试看吧:
- static int global = 100;
- int main(void)
- {
- int local = 200;
- void (^p)(void) = ^(void){
- printf("The answer is: %dn", global + local);
- global++;
- local--; // compiling error:error: decrement of read-only variable \'local\'
- };
- p();
- printf("After modified, global is: %d and local is %dn", global, local);
对 于全局变量可以进行修改,但是对于main函数中的局部变量则不行。如果对local修改则无法通过编译。很显然,Blocks对此已经有了相应的机制。 那么我们如何能够对local进行修改呢?
- static int global = 100;
- int main(void)
- {
- __block int local = 200;
- static int s = 10;
- void (^p)(void) = ^(void){
- printf("The answer is: %dn", global + local);
- global++;
- s++;
- local--;
- };
- p();
- printf("After modified, global is: %d and local is %d and s is: %dn", global, local, s);
- }
这里引入了一个新的关键字 ——__block,用此声明一个局部变量可以被函数块修改。
我们再来讨论一个更高级的话题,Blocks是否可以递归?
如果要 使Blocks能够递归,那么在函数块中必须能够引用函数块的入口地址。我做了一些尝试,当函数块引用是全局的或static的,即函数块内所引用的函数 块引用变量的值在初始时就已经确定的,那么可以使用递归。
- int main(void)
- {
- void (^p)(int) = 0;
- static void (^ const blocks)(int) = ^(int i){ if(i > 0){ puts("Hello, world!"); blocks(i - 1); } };
- p = blocks;
- p(2);
- }
如 果在上述代码中将blocks前的static去掉,那么在运行时就会出错,因为blocks在被函数块引用时是未初始化值,所以调用它的话就访问了无效 地址,或者所要执行的指令是未定义的。
各位可以再做些尝试。
下面将详细地分析一下Blocks结合泛型的使用。
由于泛型能够使我们更高效、合理地管理好自己的代码,同时也为部件化提供了许多便利之处。那么 Blocks与泛型结合会产生什么新元素呢?
我们先举一个简单例子:
- #import <Foundation/Foundation.h>
- template <void pBlock(void)>
- void BlockTest(void)
- {
- pBlock();
- }
- void Hi(void)
- {
- NSLog(@"Hi, there!");
- }
- int main(int argc, const char* argv[])
- {
- BlockTest<Hi>();
- }
上 述代码中尚未出现Blocks,但是我们可以看到,一般的外部函数能够作为模板参数。
那么Blocks是否可以这么做呢?我们不妨尝试一下:
- #import <Foundation/Foundation.h>
- template <void (^pBlock)(void)>
- void BlockTest(void)
- {
- pBlock();
- }
- int main(int argc, const char* argv[])
- {
- BlockTest<^(void) { NSLog(@"Hi, there!"); }>();
- }
编 译时会在第11行出现error: no matching function for call to \'BlockTest()\'
C++标准 中明确指出,模板参数必须为常量表达式,如果是函数的话必须是带有外部连接(即external-linkage)的函数指针。而Blocks表达式首先 就不是一个常量表达式,然后它也没有外部连接。
我们下面看第二个例子:
- #import <Foundation/Foundation.h>
- template <typename T>
- void BlockTest(void (&pBlock)(T))
- {
- pBlock(T());
- }
- static void Hi(int a)
- {
- NSLog(@"The value is: %dn", a);
- }
- int main(int argc, const char* argv[])
- {
- BlockTest(Hi);
- }
上 述代码中使用了函数引用作为函数参数,然后由实参类型演绎出模板类型。这段代码将能正常地通过编译、连接并正常运行。
那么我们下面再看一看 Blocks是否具有这个泛型特性:
- #import <Foundation/Foundation.h>
- template <typename T>
- void BlockTest(void (^pBlock)(T))
- {
- pBlock(T());
- }
- int main(int argc, const char* argv[])
- {
- BlockTest(^(int a) { NSLog(@"The value is: %dn", a); });
- }
编 译后出现 error: no matching function for call to \'BlockTest(void (^)(int))\'
即 使显式地将<int>模板实参加上也没用。也就是说Blocks的参数类型包括返回类型不能是一个泛型。
好,我们再看第三个 例子:
- #import <Foundation/Foundation.h>
- #include <iostream>
- #include <typeinfo>
- using namespace std;
- template <typename T>
- void BlockTest(T pBlock)
- {
- pBlock();
- cout << "The type is: " << typeid(T).name() << endl;
- }
- static void Hi(void)
- {
- NSLog(@"Hi, there!");
- }
- int main(int argc, const char* argv[])
- {
BlockTest(Hi);
这段代码展示了整个函数指针类型演绎出模板实参。对于目前已被很多编译器所实现的Lambda表达式,这是与泛型挂钩的唯一桥梁,那么Blocks是否具备 这个特性呢?
- #import <Foundation/Foundation.h>
- #include <iostream>
- #include <typeinfo>
- using namespace std;
- template <typename T>
- void BlockTest(T pBlock)
- {
- pBlock();
- cout << "The type is: " << typeid(T).name() << endl;
- }
- int main(int argc, const char* argv[])
- {
- BlockTest(^(void) { NSLog(@"Hi, there!"); });
- }
恭 喜,我们成功了。这段代码能够正常编译和运行。各位可以自己看看输出结果。其中,类型信息是被压缩过的:F表示函数,P表示指针,v表示void类型。
Blocks 与C++0x中的lambda表达式一样,必须作为一个完整的类型。对其类型做拆分进行泛型化是非法的。
由于C++0x的Lambda表达式的具体类型不对程序员开放,因此它即不能作为模板形参亦无法作为模板函数的形参,但是它可以在模板函数内使用泛型。
- #include <iostream>
- using namespace std;
- template <typename T>
- void LambdaTest(T)
- {
- T a = 100;
- auto ref = [a](const T& b) -> T { return a + b; };
- cout << "The value is: " << ref(200) << endl;
- }
- int main(void)
- {
- LambdaTest((short)0);
- }
上 述代码可以在VS2010β以及Intel C++ Compiler11.0通过编译并正常运行。
然而比较奇怪的是Blocks在模板函数内的 表现就非常不好——
- template <typename T>
- void BlockTest(void)
- {
- void (^pBlocks)(void) = ^{};
- }
- int main(int argc, const char* argv[])
- {
- BlockTest<void>();
- }
上 面这段代码中,模板函数BlockTest中pBlocks根本就没用泛型,也无法通过编译,而且报的错误是internal error: segmentation fault。而只有下面这种情况才能通过编译,但实际上是没有任何意义的:
- #import <Foundation/Foundation.h>
- template <typename T>
- void BlockTest(void)
- {
- void (^pBlock)(void) = nil;
- }
- int main(int argc, const char* argv[])
- {
- BlockTest<void>();
- }
可 见,Blocks作为Lambda表达式而言已经是非常棒的,但与lambda函数功能相比就稍逊一些,尤其是与泛型结合时,表现得很一般。其实这也是与 Blocks的实现有关的。Blocks仍然像objective-C的很多特性那样,主要是靠动态实现的,在编译时所花的精力较少。因此它目前也无法用 于iPhone开发,因为还需要有专门的运行时库。
我想,等到C++0x正式出台后,C++0x中的lambda表达式和lambda函数可能会 用得更多些。然而,能够在C以及objective-C中用上Lambda特性也算是一种福份了,呵呵。
- 苹果GNU C/C++,objective-C/C++新特性:Blocks
- 介绍Apple GNU C/C++,objective-C/C++中的新特性——Blocks
- Objective-C新特性
- Objective-C新特性
- Objective-C新特性
- Objective-C新特性
- Objective-c新特性
- Objective-C 新特性
- Objective-C的新特性
- Objective-C的新特性
- Objective-C的新特性
- ios6 objective-c新特性
- Objective-C的新特性
- Objective-C的新特性
- Objective-C的新特性
- objective-c 新语法特性
- Objective-C的新特性
- WWDC2013 Objective-C 新特性
- oralce 常用函数
- 加入收藏
- J2EE Spring + Hibernate + Struts整合及框架事务管理
- 推荐两个不错的包含应用程序的Linux虚拟机镜像网站
- 修改默认apn数据的方法
- 苹果GNU C/C++,objective-C/C++新特性:Blocks
- Microsoft SQL Server Integration Service文章总结---转载学习
- 一起来学REST(5)——REST服务器响应
- SVM入门(五)线性分类器的求解——问题的描述Part2
- Android process与Thread 的问题
- SVM入门(六)线性分类器的求解——问题的转化,直观角度
- 关于字符串对象的引用
- 【原创作品】爱博QQ邮件搜索机 注册机 增强补丁V2.2 (包括试用版邮箱导出补丁) 支持最新版本的 Ver 2.5.2 Build 036
- TabBarController+NavigationController 结构隐藏