• ベストアンサー

型宣言に現れる * [] () の構文要素名は?

型宣言の中に現れる "*","[]","()" (関数型を表す丸括弧) などは, 文法上は何という名前なのでしょうか? 例えば次の型宣言 (定義) char **p; int q[8]; において,手元の「ANSI C/C++ 辞典」によると, char や int は型指定子 (type specifier), **p はポインタ宣言子 (pointer declarator), q[8] は配列宣言子 (array declarator) になると思いますが, "*","[]" 単独の構文要素名は見あたりません. 個人的には * [] () のことを「型派生子」とか,曖昧に「(型派生)演算子」と呼んでいますが, 前者は上記の本にも載っていないし,検索しても全くヒットしません. 単に「演算子」だと他人に説明するとき誤解を招きそうだし….

質問者が選んだベストアンサー

  • ベストアンサー
  • MrBan
  • ベストアンサー率53% (331/615)
回答No.2

「ANSI C/C++ 辞典」なので、CなのかC++なのかわかりかねますが、 少なくともarray specifierとかpointer declaratorとかいうのは(ISO/IEC9899(C)の見出しがこうなっている)、C言語寄りっぽいですね。 ISO/IEC14882(C++)側でも別の場所で一応登場してますが、 章立てはあくまで"Declartors"の"Arrays"とか"Pointers"になって、"そういう用語"という印象はなさ気です。 # ISO/IEC14882で"array declarator"を検索すると文末のIndex内だけヒット(2件) # "pointer declarator"を検索するとIndexが1件と以下の文脈(3件)だけ(計4件) # "The * is the pointer declarator and not the multiplication operator." で、ISO/IEC14882(C++)の方ですが、 <ISO/IEC14882:2003 8 Declarators 2> The declarators specify the names of these objects, functions or typedefs, and (optionally) modify the type of the specifiers with operators such as * (pointer to) and () (function returning). </ISO/IEC14882:2003> と書いてありますので、一応operatorの一種であることは確かなようです。 # overloadの対象になる、いわゆる「演算子(multiplication operator)」とは別物なので、 # この"operator"も「演算子」と訳すかは一行の余地がありそうですけど。 # (JIS X3014は当然のごとく「演算子」と書いてありましたが…) 一応、上記で"*"と"()"はそれぞれ"pointer to", "function returing"と表現されてますが、 []については特に出てこないようです。 # 個人的には、"*"が(pointer to)なら"[]"は(array of)あたりでよさそうに思いますが…。 > 個人的には * [] () のことを「型派生子」とか,曖昧に「(型派生)演算子」と呼んでいますが, # Cでは配列(array type)等でも派生(derivation)という用語を使いますが、 # C++の場合は継承関係に用いるように整理/変更されたので、配列などはISO/IEC9899のような"derived declarator types"とは表現しなくなりました。 # C++では基本型(fundamental type)に対して配列(array type)や関数(function)のことは"compound type"と呼ばれます。 少なくともC/C++を通して「型派生子」とか「型派生演算子」というものは出てこないと思いますし、 文脈次第でそれなりに意味は取れそうですが俺様用語には変わりないですね。

noocyte
質問者

お礼

詳しい解説ありがとうございます. > 少なくともC/C++を通して「型派生子」とか「型派生演算子」というものは出てこないと思いますし、 > 文脈次第でそれなりに意味は取れそうですが俺様用語には変わりないですね。 規格書で名前が定義されていない以上,こちらで勝手に名前を付けるしかありませんし, どういう名前を付けようが「俺様用語」になってしまいます :-< それでも名前は慎重に選ばないと,誤解を招いてしまいますね. (早速招いてしまいましたし.(苦笑)) C言語を使い始めた20年ほど前,関数ポインタの構文がよくわからずモヤモヤして いたのですが,あるワークステーションのC言語のマニュアルにほんの半ページほど abstract type declaration の説明があり,* [] () の間の優先順位についても説明 していました (これらを operator と呼んでいたかどうかは覚えていませんが). これを読んで,ようやくCの型宣言がスッキリ理解できたことを覚えています. 「ANSI C/C++ 辞典」には抽象宣言子 (abstract declarator) はありますが, 抽象型宣言 (abstract type declaration) という言葉はないようです. 規格書にない言葉なんでしょうか? Google で検索してもわずかしかヒットしません. つい最近も,このカテゴリで関数ポインタのキャストに関する質問があり, 抽象型宣言の説明をして理解してもらえたばかりです. 抽象型宣言は,特に関数ポインタのキャストを理解するうえでは必須だと思いますが, これを使って型宣言やキャストの説明をしているの滅多に見かけません. (私が知らないだけ?)

noocyte
質問者

補足

(この部分は「お礼」に入れようとしたのですが,文字数オーバーになったので「補足」として投稿します.) > # Cでは配列(array type)等でも派生(derivation)という用語を使いますが、 > # C++の場合は継承関係に用いるように整理/変更されたので、配列などはISO/IEC9899のような"derived declarator types"とは表現しなくなりました。 > # C++では基本型(fundamental type)に対して配列(array type)や関数(function)のことは"compound type"と呼ばれます。 そうなんですか. データの個数に注目すると,配列は複数の要素を一つにまとめるわけですから 複合型 (compound type) になりますし,型の個数に注目すると,すべての配列 要素は同じ型で個数は1個なので,ポインタと同様に派生型と解釈できますね. C++ は前者,C は後者ですが,個人的には配列型は複合型と呼ぶ方がしっくりきます. 配列を派生型と呼ぶのは,以前から少々違和感がありましたので,その変更は歓迎します.

その他の回答 (2)

  • MrBan
  • ベストアンサー率53% (331/615)
回答No.3

> どういう名前を付けようが「俺様用語」になってしまいます :-< 前述のように、一応C++の規格書は「pointer toのような演算子」とか呼んでますが、 これで一般に通りがいいかと言われると正直疑問符がつきますしね…。 とはいえ、以下の三つは派生(複合型)の代表格ですが、それぞれ ・ポインタは"pointer to T" ・配列は"array of T" ・関数は"function returning T" と表されます(9899でも14882でもほぼ一緒)ので、先のような表現にはなるのかと思います。 # *(pointer to)のような演算子…確かにちょっと微妙。 > 規格書にない言葉なんでしょうか? C/C++仕様上の用語ではないので、少なくともISO/IEC9899やISO/IEC14882には出てきません。 > 関数ポインタの構文がよくわからずモヤモヤして "abstract declarator"の方は両方に出てきますがsyntax上の定義なので、 これについての説明が正にこの疑問に答えられたものと思われます。 ("関数の型"も考え方としては戻り値の派生でしかありません) > これを使って型宣言やキャストの説明をしているの滅多に見かけません. Semantics上は(C/C++とも)"Type name"になりますので、 一般論ではまずこちらの説明が出てくる方が多いのかと思います。 # 明らかに中~上級者が(例えばtemplateのsyntax error等で)嵌ってるとかならともかく、 # 多分、多くの質問者が背景理解から怪しそうな初心者に見えるせじゃないでしょうか。 > Google で検索してもわずかしかヒットしません。 少なくとも私は聞いたことのない用語だったので、Googleに聞いてみました。 日本語では、cflowというツールが定義してる用語と、 Javaの"abstract"型の日本語訳くらいしか出てこないですね。 英語でも大半はcflow絡み。他はJavaの"abstract"や、 その他「abstract typeがある言語」などで使われる「abstract typeのdeclaration」という文脈が圧倒的ですね。 # 一応C++にも"abstract type"(平たく言えば純粋仮想関数を含むクラス)の定義があります。 abstract declaratorの説明に出てきてもおかしくないと思いますので、 もしかすると記憶の原典はそのマニュアルだったのではないでしょうか。

参考URL:
#
noocyte
質問者

お礼

> # 明らかに中~上級者が(例えばtemplateのsyntax error等で)嵌ってるとかならともかく、 > # 多分、多くの質問者が背景理解から怪しそうな初心者に見えるせじゃないでしょうか。 やはり,そういうことなんでしょうね. 初心者がいきなり (int(*)(const void*, const void*)) なんて 構文を見せられても,目を白黒させるだけでしょうから.(笑) ありがとうございました.

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.1

規格書には特に名前は出てこなかったと思います。 *とか[ ]とか( )とかのように、そのまま記号が文中に現れています。 > 個人的には * [] () のことを「型派生子」とか,曖昧に「(型派生)演算子」と呼んでいますが, ただ、少なくとも「演算子」ではありません。 > 単に「演算子」だと他人に説明するとき誤解を招きそうだし…. 誤解を招くというより、明らかな間違いです。まだ、「記号」といった方がましでしょう。

noocyte
質問者

お礼

回答ありがとうございます. > ただ、少なくとも「演算子」ではありません。 > 誤解を招くというより、明らかな間違いです。 もちろん,C/C++ でいう演算子でないことは承知しています. ここではもっと一般的な数学的な意味で使っています. (数学用語だと「演算子」ではなく「作用素」になりますが.) 型理論において,既存の型から新しい型を作り出す操作を「演算」と 呼んでいるかどうかは知りません (検索したが見つからなかった) が, 「型演算」という言葉はあるようです.↓ http://java-house.jp/ml/archive/j-h-b/008715.html http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-list/6317

関連するQ&A

  • C言語の文法(変数宣言)について

    C言語の文法の質問をさせていただきます。 int hoge; などと宣言しますが、このintというのは型指定子というものでしょうか。 int *piyo; という宣言のintも型指定子でしょうか。 この場合、* はなんと呼ばれるのでしょうか。(アスタリスクという記号です、という回答は期待していません。(^_^;)) ポインタ宣言子、でいいのでしょうか。これは「演算子」ではないんですよね? char c[10]; という宣言の[ ]やその中に入っている10はなんと呼ばれるのでしょうか。 いま、手元に「新ANSI C言語辞典」という本があるのですが、説明を読んでもよくわかりません。

  • 「int **pt」の型と識別子名

    構文の解析をすると「int *p」は「int *」が型で「p」は識別子名でありますがポインタのポインタの場合「int **pt」の場合は「int **」が型で「pt」は識別子名でしょうか? それとも「int *」が型で「*pt」は識別子名なのでしょうか?

  • ポインタの宣言

    Cのプログラムでのポインタの宣言についてすいませんが教えてください。   int (*p)[3]; と   int *p[3]; はどのように違うのでしょうか?後輩に質問されて答えられず困っています。よろしくお願いします。

  • static付き宣言の初期化

    static付きの宣言をした場合の変数の初期化について教えてください。(ANSI-C) int func(void) { static int si; static char sca[10]; static char *scp; /* 何らかの処理 */ return 0; } このように関数内でstatic付きで宣言したとき、変数はどのように初期化されますか? siは0、sca[0]からsca[9]までは'\0'、scpはNULLで初期化されますか? また、このようなstatic付きの宣言が関数の外にあった場合は、どのように初期化されますか?

  • C言語の型と配列

    char* str[10]={"a","b"}; char* str2="c"; としたときにstr=str2とすると 型が合わないといったエラーが出ます。 でもstrって結局はポインタの配列の先頭要素のアドレスですよね。 ポインタにポインタを入れているので通るのかなと思ったんですけど、 配列で宣言するとポインタにも型がつくのでしょうか? この例だと strは char * を10個持つ配列をさすポインタ  で、 str2はchar *をさすポインタ みたいなかんじです。 質問の意味がわかりにくいですが、ご指摘をいただければ補足しますので よろしくお願いします。

  • ポインタの宣言

    ポインタを宣言するとメモリ上に、ポインタ変数を格納するための領域が確保されます。ポインタ=アドレスというのは大丈夫なのですが、 int *b のようにどうして、ポインタに型があるのでしょうか?単に変数のアドレスを表示するだけならば型はいらないと思うのですが。 またこのとき宣言された変数は *b ではなくて b であってますよね?

  • 関数原型宣言について

    関数原型宣言について 下記のプログラムのfunc関数は、関数原型宣言 <func(int a, long b, char *c);>が述されていないのにfunc関数の仮引数の型longは、関数原型宣言が与えられるといると本に書かれていたのですが、何故でしょうか教えて頂きたい。 ******************************************** #include <stdio.h> /*--- 三つの引数を受け取る関数 ---*/ void func(int a, long b, char *c) { int x; long y; /* … */ } int main(int argc, char *argv[]) { int a = 1; char s[] = "abc"; func(a + 3, 2, s); return (0); } *************************************************************

  • 関数の引数をvoid*でキャストする

    最近見かけたCのプログラムで、関数の引数の型は void* なのですが、その関数を使うときに 引数をvoid*でキャストしていました。 例えば、 func ( (void*) p ); こういうことです。 私の知っている知識では、 void* と 任意の型のポインタは キャストなしに相互に代入可能です。 関数の引数でも、キャストは要らないものだと思っていました。 そうすると、引数を void* でキャストするのは無意味だと思うのですが、・・・ 違うのでしょうか。処理系によるとか。 逆に、関数の引数の型がchar*などで、渡すものが void* のときはどうなのでしょうか。 下のプログラムは、関数byte_orderの引数の型はvoid*ですが、int型へのポインタ( &a )を設定しています。私の環境では、コンパイルエラーも警告もないし、動作も正常です。 #include <stdio.h> #include <string.h> void byte_order(void *vp) { char char_array[4]; strncpy(char_array, vp, 4); printf("出力します:%x %x %x %x\n", char_array[0], char_array[1], char_array[2], char_array[3]); } int main(void) { int a = 0x12345678; byte_order(&a); return 0; } このプログラムは単なる一例であって、質問はバイトオーダに関するものではありません。 また、C言語の質問であって、C++ではありません。

  • char* 宣言での配列要素アクセスについて

    char* 宣言での配列要素アクセスについて char*型で宣言したポインタ変数に対して 配列の要素でアクセスすると落ちてしまいます。 理由がよくわかりません。 以下コードになります。 (コードA) char* pA = "123456789"; pA[2] = 'A'; 以下のコードの場合は問題ありません。 (コードB) char pB[] = "123456789"; pB[2] = 'B'; 両者の違いがいまいちよく分かりません。 コードAでpA[2]のアドレスを確認すると、 pAのアドレス[+2]を指しているので問題ないともうのですが、 間違っているのでしょうか? pAに対して特別な操作はしていません。 ご教授お願いいたします。

  • strchr() の第2引数はなぜ int 型なのでしょうか

    もしかすると、ちょい前の質問(https://okauth.okwave.jp/qa4151232.html)と同じことを聞いているような気もしますが、気にせずポスト。 その質問を読んだ時に strchr() のマニュアルを見たわけなんですが、そのプロトタイプ宣言は char* strchr(const char* s, int c); なんですね。どうして第 2 引数の型が int なのでしょう?「文字」c を検索するんだから普通に考えれば char ではないかと思うのですが、誰か教えて下さい。 ソースはこんな感じだったので、int である必要はないように思えるのですがどうなんでしょうか? 負数を与えたときに「何らかの動作」を期待してのことなのでしょうか? char* strchr(const char* s, int c) {  char ch;  ch = c; /* <= 結局 char 型にしている */  for ( ; ; ++s) {   if ( *s == ch ) {    return (char*)s;   }   if ( *s == '\0' ) {    return NULL;   }  } }

専門家に質問してみよう