post-Pittsburgh mailingの公開まで、いよいよ日が迫ってきた。FCDが公開されたならば、直ちに変更点を把握して、参考書の執筆を始めなければならない。
ところで、実は、いまもって、よく理解出来ないことがひとつある。attributeだ。
attributeがよく分からない。というのも、あまりにも、記述出来る場所が多すぎるので、一体、どこに書いていいのか、迷うのだ。
たとえば、ある変数に対して、アラインメントを指定したいとしよう。
// 16バイトにアラインメントされてほしい。 char buffer[64] ;
目的は様々だが、とにかく、この変数が、16バイトのアラインメントされていてほしい。では、既存のコンパイラは、どのような拡張機能を提供しているのだろうか。
MSVCの場合、__declspecというキーワードの、一種の、specifierが存在する。以下のように使う。
// どちらも同じ意味。 __declspec( align(16) ) char buffer1[64] ; char __declspec( align(16) ) buffer2[64] ;
GCCの場合、__alignof__や、__attribute__という、キーワードがある。
// すべて同じ意味。 __attribute__ ((aligned (16))) char buffer1[60] ; char __attribute__ ((aligned (16))) buffer2[60] ; char buffer3 [60] __attribute__ ((aligned (16))) ;
両者とも、何とも、ファジーな文法ではある。
まず、C++0xの、attributeの文法を見てみる。attributeは、実に様々な場所に、記述できる。
[[/* #1 */]] char [[/* #2 */]] buffer [[/* #3 */]] [64] [[/* #4 */]] ;
さて、アラインメントは、どこに記述すればいいのだろうか。
7.6.2 Alignment attribute [dcl.align] p1を読むと、アラインメントのattributeは、「関数パラメーターか、register」以外の(つまり、関数パラメーターや、registerな変数には指定できないという意味)、変数(Variable)か、クラスのデーターメンバー(ただし、ビットフィールドを除く)に指定できる、と書いてある。
この文、非常にわかりにくかったので、わかりやすく改行して引用する。
The attribute can be applied
to a variable that is neither(i.e except followings)
a function parameter
nor
declared with the register storage class specifier
and(can be applied)
to a class data member that is not a bit-field.
ということは、一箇所にしか記述できない。すなわち、#3である。
唯一の正しい例は、以下の通りである。
// well-formed. char buffer [[ align(16)]] [64] ;
以下はすべて、間違った例である。
// ill-formed. [[ align(16)]] char buffer[64] ; char [[ align(16)]] buffer[64] ; char buffer[64] [[ align(16)]] ;
何故か。そもそも、variableというのは、3 Basic concepts [basic] p6に書いてあるように、宣言文によってもたらされる、名前(name)である。ここで、変数の名前とは、bufferである。では、この名前にattributeを指定したい場合は、どこに書けばいいのか。
8 Declarators [dcl.decl] p4に書いてあるように、
noptr-declarator: declarator-id attribute-specifieropt
である。つまり、名前の直後に、attributeを指定しなければならない。
この、variable(変数)に対して、指定しなければならないというのは、統一的で、分かりやすい文法である。というのも、C++は、ひとつの宣言文で、複数の変数を宣言できる言語である。
int (*a)(int), b ;
一目瞭然であるが、aは、関数ポインタ型であり、bは、int型である。もし、以下のように、アラインメントattributeを指定できるとしたら、どうにも、言語の文法的に、分かりにくい。
// これはエラー [[align(16)]] int (*a)(int), b ; int (*a [[align(16)]] )(int), b [[align(16)]] ;
変数(つまり、変数の名前)に指定するというルールは、文法的には、分かりやすい。ただ、どうも、人間には、わかりやすくないと思う。
int (*a [[align(16)]] [10])(int) ;
まあ、これは、極端な例で、関数ポインタの配列をアラインメントしたいという事は、あまりないだろうが。
基本的に、標準のattributeはすべて、名前に付くとしておけば、とりあえず、参考書の解説としては、分かりやすいだろうか。どうもこの詳細は、参考書で書いても、無駄にページを浪費するだけだと思う。
No comments:
Post a Comment