8.2 通用属性
类别:部分人
8.2.1 语言扩展到通用属性
随着C++语言的演化和编译器的发展,人们常会发现标准提供的语言能力不能完全满足要求。于是编译器厂商或组织为了满足编译器客户的需求,设计出了一系列的语言扩展(language extension)来扩展语法。这些扩展语法并不存在于C++/C标准中,却有可能拥有较多的用户。有的时候,新的标准也会将广泛使用的语言扩展纳入其中。
扩展语法中比较常见的就是“属性”(attribute)。属性是对语言中的实体对象(比如函数、变量、类型等)附加一些的额外注解信息,其用来实现一些语言及非语言层面的功能,或是实现优化代码等的一种手段。
不同编译器有不同的属性语法。比如对于g++,属性是通过GNU的关键字attribute来声明的。程序员只需要简单地声明:
attribute((attribute-list))
即可为程序中的函数、变量和类型设定一些额外信息,以便编译器可以进行错误检查和性能优化等。我们可以看看代码清单8-9所示的例子。
代码清单8-9
extern int area(int n)attribute((const));
int main(){
int i;
int areas=0;
for(i=0;i<10;i++){
areas+=area(3)*i;
}
}
//编译选项:g++ -c 8-2-1.cpp
这里的const属性告诉编译器:本函数返回值只依赖于输入,不会改变任何函数外的数据,因此没有任何副作用。在了解该信息的情况下,编译器可以对area函数进行优化处理。area(3)的值只需要计算一次,编译之后可以将area(3)视为循环中的常量而只使用其计算结果,从而大大提高了程序的执行性能。
注意 事实上,在GNU对C/C++的扩展中我们可以看到很多不同的attribute属性。常见的如format、noreturn、const和aligned等,具体含义和用法读者可以参考GNU的在线文档http://gcc.gnu.org/onlinedocs/。
而在Windows平台上,我们会找到另外一种关键字declspec。declspec是微软用于指定存储类型的扩展属性关键字。用户只要简单地在声明变量时加上:
__declspec(extended-decl-modifier)
即可设定额外的功能。以对齐方式为例,在C++11之前,微软平台的程序员可以使用__declspec(align(x))来控制变量的对齐方式,如代码清单8-10所示。
代码清单8-10
__declspec(align(32))struct Struct32{
int i;
double d;
};
在代码清单8-10中,结构体Struct32被对齐到32字节的地址边界,其起始地址必须是32的倍数。这跟C++11中alignas的效果是一样的。
注意 同样的,微软也定义了很多__declspec属性,如noreturn、oninline、align、dllimport、dllexport等,具体含义和用法可以参考微软网站上的介绍:http://msdn.microsoft.com/en-US/library/。
事实上,在扩展语言能力的时候,关键字往往会成为一种选择。GNU和微软只能选择“属性”这样的方式,是为了尽可能避免与用户自定义的名称冲突。同样,在C++11标准的设立过程中,也面临着关键字过多的问题。于是C++11语言制定者决定增加了通用属性这个特性。不过C++11的通用属性设计跟GNU和微软都不一样,至少直观地看来,其更加简洁。